Course Contents

  1. 2022.12.07: Introduction: About the course [lead by TK]
    • An introduction to open and public data, and data science
  2. 2022-12-14: Exploratory Data Analysis (EDA) 1 [lead by hs]
    • R Basics with RStudio and/or RStudio.cloud; Toy Data
  3. 2022-12-21: Exploratory Data Analysis (EDA) 2 [lead by hs]
    • R Markdown, tidyverse I: dplyr; gapminder
  4. 2023-01-11: Exploratory Data Analysis (EDA) 3 [lead by hs]
    • tidyverseII: readr, ggplot2; Public Data, WDI, WIR, etc
  5. 2023-01-18: Exploratory Data Analysis (EDA) 4 [lead by hs]
    • tidyverse III: tidyr, etc.; WDI, WIR, etc
  6. 2023-01-25: Exploratory Data Analysis (EDA) 5 [lead by hs]
    • tidyverse IV; WDI, WIR, etc
  7. 2023-02-01: Introduction to PPDAC
    • Problem-Plan-Data-Analysis-Conclusion Cycle: [lead by TK]
  8. 2023-02-08: Model building I [lead by TK]
    • Collecting and visualizing data and Introduction to WDI
      (World Development Indicators by World Bank)
  9. 2023-02-15: Model building II [lead by TK]
    • Analyzing data and communications
  10. 2023-02-22: Project Presentation

1 Exploratory Data Analysis (EDA) I

1.1 R with R Studio and/or R Studio.cloud


1.1.1 Learning Resources

1.1.1.1 Textbooks and References

1.1.2 Interactive Exercises


1.1.3 Posit Primers created by learnr

1.1.3.1 Posit Primers https://posit.cloud/learn/primers

  1. The Basics – r4ds: Explore, I
  1. Work with Data – r4ds: Wrangle, I
  • Working with Tibbles
  • Isolating Data with dplyr
  • Deriving Information with dplyr
  1. Visualize Data – r4ds: Explore, II
  2. Tidy Your Data – r4ds: Wrangle, II
  3. Iterate – r4ds: Program
  4. Write Functions – r4ds: Program

1.1.4 Data Science and EDA

1.1.4.1 Wikipedia https://en.wikipedia.org/wiki/Data_science

An inter-disciplinary field that uses scientific methods, processes, algorithms and systems to extract knowledge and insights from many structural and unstructured data.

  • Create Insights
  • Impact Decision Making
  • Maintain & Improve Overtime

1.1.5 What is R?

1.1.5.1 R (programming language), Wikipedia

  • R is a programming language and free software environment for statistical computing and graphics supported by the R Foundation for Statistical Computing.

  • The R language is widely used among statisticians and data miners for developing statistical software and data analysis.

  • A GNU package, the official R software environment is written primarily in C, Fortran, and R itself (thus, it is partially self-hosting) and is freely available under the GNU General Public License.


1.1.5.2 History of R and more

“R Programming for Data Science” by Roger Peng


1.1.6 Why R? – Responses by Hadley Wickham

1.1.6.1 r4ds: R is a great place to start your data science journey because

  • R is an environment designed from the ground up to support data science.
  • R is not just a programming language, but it is also an interactive environment for doing data science.
  • To support interaction, R is a much more flexible language than many of its peers.

1.1.6.2 Why R today?

When you talk about choosing programming languages, I always say you shouldn’t pick them based on technical merits, but rather pick them based on the community. And I think the R community is like really, really strong, vibrant, free, welcoming, and embraces a wide range of domains. So, if there are like people like you using R, then your life is going to be much easier. That’s the first reason.

Interview: “Advice to Young (and Old) Programmers, H. Wickham”


1.1.7 What is RStudio? https://posit.com

RStudio is an integrated development environment, or IDE, for R programming.

1.1.7.1 R Studio (Wikipedia)

RStudio is an integrated development environment (IDE) for R, a programming language for statistical computing and graphics. It is available in two formats: RStudio Desktop is a regular desktop application while RStudio Server runs on a remote server and allows accessing RStudio using a web browser.


1.1.8 Installation of R and R Studio

1.1.8.1 R Installation

To download R, go to CRAN, the comprehensive R archive network. CRAN is composed of a set of mirror servers distributed around the world and is used to distribute R and R packages. Don’t try and pick a mirror that’s close to you: instead use the cloud mirror, https://cloud.r-project.org, which automatically figures it out for you.

A new major version of R comes out once a year, and there are 2-3 minor releases each year. It’s a good idea to update regularly.

1.1.8.2 R Studio Installation

Download and install it from http://www.rstudio.com/download.

RStudio is updated a couple of times a year. When a new version is available, RStudio will let you know.


1.1.9 R Studio

1.1.9.1 The First Step

  1. Start R Studio Application
  2. Top Menu: File > New Project > New Directory > New Project > Directory name or Browse the directory and choose the parent directory you want to create the directory

1.1.9.2 When You Start the Project

  1. Go to the directory you created
  2. Double click _‘Directory Name’.Rproj

Or,

  1. Start R Studio
  2. File > Open Project (or choose from Recent Project)

In this way the working directory of the session is set to the project directory and R can search releted files without difficulty (getwd(), setwd())


1.1.10 Posit Cloud

RStudio Cloud is a lightweight, cloud-based solution that allows anyone to do, share, teach and learn data science online.

1.1.10.1 Cloud Free

  • Up to 15 projects total
  • 1 shared space (5 members and 10 projects max)
  • 15 project hours per month
  • Up to 1 GB RAM per project
  • Up to 1 CPU per project
  • Up to 1 hour background execution time

1.1.10.2 How to Start Posit Cloud

  1. Go to https://posit.cloud/
  2. Sign Up: top right
  • Email address or Google account
  1. New Project: Project Name
  2. R Console

1.2 Let’s Get Started

Start RStudio and create a project, or login to Posit Cloud and create a project.


1.2.1 The First Examples

Input the following codes into Console in the left bottom pane.

  • The first two:
head(cars)

str(cars)
'data.frame':   50 obs. of  2 variables:
 $ speed: num  4 4 7 7 8 9 10 10 10 11 ...
 $ dist : num  2 10 4 22 16 10 18 26 34 17 ...

  • Two more:
summary(cars)
     speed           dist       
 Min.   : 4.0   Min.   :  2.00  
 1st Qu.:12.0   1st Qu.: 26.00  
 Median :15.0   Median : 36.00  
 Mean   :15.4   Mean   : 42.98  
 3rd Qu.:19.0   3rd Qu.: 56.00  
 Max.   :25.0   Max.   :120.00  

plot(cars)


  • And three more:
plot(cars) # cars: Speed and Stopping Distances of Cars
abline(lm(cars$dist~cars$speed))


lm(cars$dist~cars$speed)

Call:
lm(formula = cars$dist ~ cars$speed)

Coefficients:
(Intercept)   cars$speed  
    -17.579        3.932  

summary(lm(cars$dist~cars$speed))

Call:
lm(formula = cars$dist ~ cars$speed)

Residuals:
    Min      1Q  Median      3Q     Max 
-29.069  -9.525  -2.272   9.215  43.201 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -17.5791     6.7584  -2.601   0.0123 *  
cars$speed    3.9324     0.4155   9.464 1.49e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 15.38 on 48 degrees of freedom
Multiple R-squared:  0.6511,    Adjusted R-squared:  0.6438 
F-statistic: 89.57 on 1 and 48 DF,  p-value: 1.49e-12

1.2.1.1 Brief Explanation

  • head(cars): The first 6 rows of the pre-installed data cars.
  • str(cars): The data structure of the pre-installed data cars.
  • summary(cars): The summary of the pre-installed data cars.
  • plot(cars): A scatter plot of the pre-installed data cars.
    • plot(cars$dist~cars$speed)
    • cars$dist, cars$[[2]], cars[,2] are same
  • abline(lm(cars$dist~cars$speed)): Add a regression line of a linear model
  • lm(cars$dist~cars$speed): The equation of the regression line
  • summary(lm(cars$dist~cars$speed): The summary of the linear regression model

hist(cars$dist)


hist(cars$speed)


1.2.1.2 View and help

  • View(cars)
  • ?cars: same as help(cars)
  • ??cars: same as `help.search(“cars”)

1.2.1.3 datasets

  • ?datasets

  • library(help = "datasets")

  • data() shows all data already attached and available.


1.2.2 Practicum

Pick a data in the datasets package and try

  • head()
  • str()
  • summary()

and some more.


1.2.2.1 iris

head(iris)

str(iris)
'data.frame':   150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

summary(iris)
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
       Species  
 setosa    :50  
 versicolor:50  
 virginica :50  
                
                
                

Can you plot?

plot(iris$Sepal.Length, iris$Sepal.Width)

1.3 tidyverse Packages

1.3.1 Brief Introduction to R on RStudio

1.3.1.1 Four Panes and Tabs

  1. Top Left: Source Editor
  2. Top Right: Environment, History, etc.
  3. Bottom Left: Console, Terminal, Render, Background Jobs
  4. Bottom Right: Files, Plots, Packages, Help, Viewer, Presentation

1.3.1.2 Set up

  • Highly recommend to set the language to be “English”.
  • Create “data” directory.
Sys.setenv(LANG = "en")
dir.create("data")

1.3.1.3 Three Ways to Run Codes

  1. Console - Bottom Left Pane
  2. R Script - pull down menu under File
  3. R Notebook, R Markdown - pull down menu under File

1.3.2 Second Way: R Script

1.3.2.1 Examples: R Scripts in Moodle

  • basics.R
  • coronavirus.R
  1. Copy a script in Moodle: {file name}.R
  2. In RStudio (create Project in RStudio) choose File > New File > R Script and paste it.
  3. Choose File > Save with a name; e.g. {file names} (.R will be added automatically)

To run a code: at the cursor press Ctrl+Shift+Enter (Win) or Cmd+Shift+Enter (Mac).


1.3.3 Packages

R packages are extensions to the R statistical programming language. R packages contain code, data, and documentation in a standardised collection format that can be installed by users of R, typically via a centralised software repository such as CRAN (the Comprehensive R Archive Network).

1.3.3.1 Installation and attachement

You can install packages by “Install Packages…” under “Tool” in the top menu.

  • install.packages("tidyverse")
  • install.packages("rmarkdown")

1.3.4 Third Way: R Notebook

Choose R Notebook from the pull down File menu in the top bar.

1.3.5 Edit YAML

Default* is as follows

---
title: "R Notebook"
output: html_notebook
---

Template

---
title: "Title of R Notebook"
author: "ID and Your Name"
date: "2023-01-26" 
output: 
  html_notebook:
#    number_sections: yes
#    toc: true
#    toc_float: true
---
  • Don’t change the format. Indention matters.
  • The statement after # is ignored.
  • Date is automatically inserted when you compile the file.
  • You can replace “2023-01-26” by “2022-12-14” or in any date format surrounded by double quotation marks.
  • Section numbers: - default is number_sections: no.
  • Table of contents, toc: true - default is toc: false.
  • Floating table of contents in HTML output, toc_float: true - default is toc_float: false

1.3.6 Create a Code Chunk to Attach Packages

Insert Chunk in Code pull down menu in the top bar, or use the C button on top. You can use shortcut keys listed under Tools in the top bar.

library(tidyverse)

1.4 First Example

1.4.1 Importing data

Let us assign the iris data in the pre-installed package datasets to df_iris. You can give any name starting from an alphabet, though there are some rules.

df_iris <- datasets::iris
class(df_iris)
[1] "data.frame"

The class of data iris is data.frame, the basic data class of R. You can assign the same data as a tibble, the data class of tidyverse as follows.

tbl_iris <- as_tibble(datasets::iris)
class(tbl_iris)
[1] "tbl_df"     "tbl"        "data.frame"
  • df_iris <- iris can replace df_iris <- datasets::iris because the package datasets is installed and attached as default. Since you may have other data called iris included in a different package or you may have changed iris before, it is safer to specify the name of the package with the name of the data.
  • Within R Notebook or in Console, you may get different output, and tf_iris and tbl_iris behave differently. It is because of the default settings of R Markdown.

1.4.2 Look at the data

1.4.2.1 Several ways to view the data.

The View command open up a window to show the contents of the data and you can use the filter as well.

View(df_iris)

The following simple command also shows the data.

df_iris

The output within R Notebook is a tibble style. Try the same command in Console.


slice(df_iris, 1:10)
1:10
 [1]  1  2  3  4  5  6  7  8  9 10

1.5 `

1.5.0.1 Data Structure

Let us look at the structure of the data. You can try str(df_iris) on Console or by adding a code chunk in R Notebook introducing later.

glimpse(df_iris)
Rows: 150
Columns: 5
$ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4,…
$ Sepal.Width  <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9,…
$ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4,…
$ Petal.Width  <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2,…
$ Species      <fct> setosa, setosa, setosa, setosa, setosa, seto…

There are six types of data in R; Double, Integer, Character, Logical, Raw, Complex.

The names after $ are column names. If you call df_iris$Species, you have the Species column. Species is in the 5th collumn, typeof(df_iris[[5]]) does the same as the next.

df_iris[2,4] =

is the fourth entry of Sepal.Width.


typeof(df_iris$Species)
[1] "integer"
class(df_iris$Species)
[1] "factor"

For factors = fct see the R Document or an explanation in Factor in R: Categorical Variable & Continuous Variables.


typeof(df_iris$Sepal.Length)
[1] "double"
class(df_iris$Sepal.Length)
[1] "numeric"

Q1. What are the differences ofdf_iris, slice(df_iris, 1:10) and glimpse(df_iris) above?

Q2. What are the differences ofdf_iris, slice(df_iris, 1:10) and glimpse(df_iris) in the console?


1.5.0.2 Summary of the Data

The following is very convenient to get the summary information of a data.

summary(df_iris)
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
       Species  
 setosa    :50  
 versicolor:50  
 virginica :50  
                
                
                

Minimum, 1st Quadrant (25%), Median, Mean, 3rd Quadrant (75%), Maximum, and the count of each factor.


1.5.1 Visualizing Data

1.5.1.1 Scatter Plot

We use ggplot to draw graphs. The scatter plot is a projection of data with two variables \(x\) and \(y\).

ggplot(data = <data>, aes(x = <column name for x>, y = <column name for y>)) +
  geom_point()
ggplot(data = df_iris, aes(x = Sepal.Length, y = Sepal.Width)) +
  geom_point()

ggplot(data = df_iris, aes(x = Sepal.Length, y = Sepal.Width)) +
  geom_point()


1.5.1.2 Scatter Plot with Labels

Add title and labels adding labs().

ggplot(data = <data>, aes(x = <column name for x>, y = <column name for y>)) +
  geom_point() +
  labs(title = "Title", x = "Label for x", y = "Label for y")

ggplot(data = df_iris, aes(x = Sepal.Length, y = Sepal.Width)) +
  geom_point() + 
  labs(title = "Scatter Plot of Sepal Data of Iris", x = "Sepal Length", y = "Sepal Width")


1.5.1.3 Scatter Plot with Colors

Add different colors automatically to each species. Can you see each group?

ggplot(data = df_iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point()


1.5.1.4 Scatter Plot with Shapes

ggplot(data = df_iris, aes(x = Sepal.Length, y = Sepal.Width, shape = Species)) +
  geom_point()


1.5.1.5 Boxplot

The boxplot compactly displays the distribution of a continuous variable.

ggplot(data = df_iris, aes(x = Species, y = Sepal.Length)) +
  geom_boxplot()


1.5.1.6 Histogram

Visualize the distribution of a single continuous variable by dividing the x axis into bins and counting the number of observations in each bin. Histograms (geom_histogram()) display the counts with bars.

ggplot(data = df_iris, aes(x = Sepal.Length)) +
  geom_histogram()


Change the number of bins by bins = <number>.

ggplot(data = df_iris, aes(x = Sepal.Length)) +
  geom_histogram(bins = 10)


1.5.2 Data Modeling

Professor Kaizoji will cover the mathematical models and hypothesis testings.

ggplot(data = df_iris, aes(x = Sepal.Length, y = Sepal.Width)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE)

1.6 Comments on Week 2

1.6.0.2 Practicum


1.6.0.3 Assignments - See Moodle

  1. Assignment Week 2-1: Introduction Plus Forum
  • Due: Tuesday, 20 December 2022, 11:59 PM
  1. Assignment Week 2-2: Quiz 1 on R Basics
  • Due: Tuesday, 20 December 2022, 11:59 PM

1.7 Swirl: An interactive learning environment for R and statistics

1.7.1 Swirl Courses

  1. R Programming: The basics of programming in R
  2. Regression Models: The basics of regression modeling in R
  3. Statistical Inference: The basics of statistical inference in R
  4. Exploratory Data Analysis: The basics of exploring data in R

You can install other swirl courses as well


1.7.2 Install and Start Swirl Courses

1.7.2.1 Three Steps to Start Swirl

install.packages("swirl") # Only the first time.
library(swirl) # Everytime you start swirl
swirl() # Everytime you start or resume swirl

1.7.2.2 R Programming: The basics of programming in R

 1: Basic Building Blocks      2: Workspace and Files     3: Sequences of Numbers    
 4: Vectors                    5: Missing Values          6: Subsetting Vectors      
 7: Matrices and Data Frames   8: Logic                   9: Functions               
10: lapply and sapply         11: vapply and tapply      12: Looking at Data         
13: Simulation                14: Dates and Times        15: Base Graphics          

1.7.2.4 Controling a swirl Session

  • … <– That’s your cue to press Enter to continue

  • You can exit swirl and return to the R prompt (>) at any time by pressing the Esc key.

  • If you are already at the prompt, type bye() to exit and save your progress. When you exit properly, you’ll see a short message letting you know you’ve done so.

When you are at the R prompt (>):

  1. Typing skip() allows you to skip the current question.
  2. Typing play() lets you experiment with R on your own; swirl will ignore what you do…
  3. UNTIL you type nxt() which will regain swirl’s attention.
  4. Typing bye() causes swirl to exit. Your progress will be saved.
  5. Typing main() returns you to swirl’s main menu.
  6. Typing info() displays these options again.

1.7.2.5 Final Remark

You will encounter the message like ‘Would you like to receive credit for completing this course on Coursera.org?’ at the end of each course. This is for coursera courses. Select ‘NO’.

1.8 More on R Script: Examples

1.8.1 R Scripts in Moodle

  • basics.R
  • coronavirus.R
  1. Copy a script in Moodle: {file name}.R
  2. In RStudio (Workspace in RStudio.cloud, Project in RStudio) choose File > New File > R Script and paste it.
  3. Choose File > Save with a name; e.g. {file names} (.R will be added automatically)

1.8.2 basics.R

The script with the outputs.

#################
#
# basics.R
#
################
# 'Quick R' by DataCamp may be a handy reference: 
#     https://www.statmethods.net/management/index.html
# Cheat Sheet at RStudio: https://www.rstudio.com/resources/cheatsheets/
# Base R Cheat Sheet: https://github.com/rstudio/cheatsheets/raw/main/base-r.pdf
# To execute the line: Control + Enter (Window and Linux), Command + Enter (Mac)
## try your experiments on the console

## calculator

3 + 7

### +, -, *, /, ^ (or **), %%, %/%

3 + 10 / 2

3^2

2^3

2*2*2

### assignment: <-, (=, ->, assign()) 

x <- 5

x 

#### object_name <- value, '<-' shortcut: Alt (option) + '-' (hyphen or minus) 
#### Object names must start with a letter and can only contain letter, numbers, _ and .

this_is_a_long_name <- 5^3

this_is_a_long_name

char_name <- "What is your name?"

char_name

#### Use 'tab completion' and 'up arrow'

### ls(): list of all assignments

ls()
ls.str()

#### check Environment in the upper right pane

### (atomic) vectors

5:10

a <- seq(5,10)

a

b <- 5:10

identical(a,b)

seq(5,10,2) # same as seq(from = 5, to = 10, by = 2)

c1 <- seq(0,100, by = 10)

c2 <- seq(0,100, length.out = 10)

c1

c2

length(c1)

#### ? seq   ? length   ? identical

(die <- 1:6)

zero_one <- c(0,1) # same as 0:1

die + zero_one # c(1,2,3,4,5,6) + c(0,1). re-use

d1 <- rep(1:3,2) # repeat


d1

die == d1

d2 <- as.character(die == d1)

d2

d3 <- as.numeric(die == d1)

d3

### class() for class and typeof() for mode
### class of vectors: numeric, charcters, logical
### types of vectors: doubles, integers, characters, logicals (complex and raw)

typeof(d1); class(d1)

typeof(d2); class(d2)

typeof(d3); class(d3)

sqrt(2)

sqrt(2)^2

sqrt(2)^2 - 2

typeof(sqrt(2))

typeof(2)

typeof(2L)

5 == c(5)

length(5)

### Subsetting

(A_Z <- LETTERS)

A_F <- A_Z[1:6]

A_F

A_F[3]

A_F[c(3,5)]

large <- die > 3

large

even <- die %in% c(2,4,6)

even

A_F[large]

A_F[even]

A_F[die < 4]

### Compare df with df1 <- data.frame(number = die, alphabet = A_F)
df <- data.frame(number = die, alphabet = A_F, stringsAsFactors = FALSE)

df

df$number

df$alphabet

df[3,2]

df[4,1]

df[1]

class(df[1])

class(df[[1]])

identical(df[[1]], die)

identical(df[1],die)

####################
# The First Example
####################

plot(cars)

# Help

? cars

# cars is in the 'datasets' package

data()

# help(cars) does the same as ? cars
# You can use Help tab in the right bottom pane

help(plot)
? par

head(cars)

str(cars)

summary(cars)

x <- cars$speed
y <- cars$dist

min(x)
mean(x)
quantile(x)

plot(cars)

abline(lm(cars$dist ~ cars$speed))

summary(lm(cars$dist ~ cars$speed))

boxplot(cars)

hist(cars$speed)
hist(cars$dist)
hist(cars$dist, breaks = seq(0,120, 10))

1.8.3 coronavirus.R

The script and its outputs. coronavirus.csv is very large

# https://coronavirus.jhu.edu/map.html
# JHU Covid-19 global time series data
# See R pakage coronavirus at: https://github.com/RamiKrispin/coronavirus
# Data taken from: https://github.com/RamiKrispin/coronavirus/tree/master/csv
# Last Updated
Sys.Date()

## Download and read csv (comma separated value) file
coronavirus <- read.csv("https://github.com/RamiKrispin/coronavirus/raw/master/csv/coronavirus.csv")
# write.csv(coronavirus, "data/coronavirus.csv")

## Summaries and structures of the data
head(coronavirus)
str(coronavirus)
coronavirus$date <- as.Date(coronavirus$date)
str(coronavirus)

range(coronavirus$date)
unique(coronavirus$country)
unique(coronavirus$type)

## Set Country
COUNTRY <- "Japan"
df0 <- coronavirus[coronavirus$country == COUNTRY,]
head(df0)
tail(df0)
(pop <- df0$population[1])
df <- df0[c(1,6,7,13)]
str(df)
head(df)
### alternatively,
head(df0[c("date", "type", "cases", "population")])
###

## Set types
df_confirmed <- df[df$type == "confirmed",]
df_death <- df[df$type == "death",]
df_recovery <- df[df$data_type == "recovery",]
head(df_confirmed)
head(df_death)
head(df_recovery)

## Histogram
plot(df_confirmed$date, df_confirmed$cases, type = "h")
plot(df_death$date, df_death$cases, type = "h")
# plot(df_recovered$date, df_recovered$cases, type = "h") # no data for recovery

## Scatter plot and correlation
plot(df_confirmed$cases, df_death$cases, type = "p")
cor(df_confirmed$cases, df_death$cases)


## In addition set a period
start_date <- as.Date("2021-07-01")
end_date <- Sys.Date() 
df_date <- df[df$date >=start_date & df$date <= end_date,]
##

## Set types
df_date_confirmed <- df_date[df_date$type == "confirmed",]
df_date_death <- df_date[df_date$type == "death",]
df_date_recovery <- df_date[df_date$data_type == "recovery",]
head(df_date_confirmed)
head(df_date_death)
head(df_date_recovery)

## Histogram
plot(df_date_confirmed$date, df_date_confirmed$cases, type = "h")
plot(df_date_death$date, df_date_death$cases, type = "h")
# plot(df_date_recovered$date, df_date_recovered$cases, type = "h") # no data for recovery

plot(df_date_confirmed$cases, df_date_death$cases, type = "p")
cor(df_date_confirmed$cases, df_date_death$cases)

### Q0. Change the values of the location and the period and see the outcomes.
### Q1. What is the correlation between df_confirmed$cases and df_death$cases?
### Q2. Do we have a larger correlation value if we shift the dates to implement the time-lag?
### Q3. Do you have any other questions to explore?

#### Extra
plot(df_confirmed$date, df_confirmed$cases, type = "h", 
     main = paste("Comfirmed Cases in",COUNTRY), 
     xlab = "Date", ylab = "Number of Cases")

:::

1.9 gapminder Package

1.9.1 Hans Rosling (1948 – 2017)

Hans Rosling was a Swedish physician, academic, and public speaker. He was a professor of international health at Karolinska Institute[4] and was the co-founder and chairman of the Gapminder Foundation, which developed the Trendalyzer software system. (wikipedia)


1.9.2 Factfulness is … From the book

recognizing when a decision feels urgent and remembering that it rarely is.

To control the urgency instinct, take small steps.

  • Take a breath. When your urgency instinct is triggered, your other instincts kick in and your analysis shuts down. Ask for more time and more information. It’s rarely now or never and it’s rarely either/or.
  • Insist on the data. If something is urgent and important, it should be measured. Beware of data that is relevant but inaccurate, or accurate but irrelevant. Only relevant and accurate data is useful.
  • Beware of fortune-tellers. Any prediction about the future is uncertain. Be wary of predictions that fail to acknowledge that. Insist on a full range of scenarios, never just the best or worst case. Ask how often such predictions have been right before.
  • Be wary of drastic action. Ask what the side effects will be. Ask how the idea has been tested. Step-by-step practical improvements, and evaluation of their impact, are less dramatic but usually more effective.

# install.packages("gapminder")
library(gapminder)
df <- gapminder
df

glimpse(df)
Rows: 1,704
Columns: 6
$ country   <fct> "Afghanistan", "Afghanistan", "Afghanistan", "A…
$ continent <fct> Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia,…
$ year      <int> 1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987,…
$ lifeExp   <dbl> 28.801, 30.332, 31.997, 34.020, 36.088, 38.438,…
$ pop       <int> 8425333, 9240934, 10267083, 11537966, 13079460,…
$ gdpPercap <dbl> 779.4453, 820.8530, 853.1007, 836.1971, 739.981…

summary(df)
        country        continent        year         lifeExp     
 Afghanistan:  12   Africa  :624   Min.   :1952   Min.   :23.60  
 Albania    :  12   Americas:300   1st Qu.:1966   1st Qu.:48.20  
 Algeria    :  12   Asia    :396   Median :1980   Median :60.71  
 Angola     :  12   Europe  :360   Mean   :1980   Mean   :59.47  
 Argentina  :  12   Oceania : 24   3rd Qu.:1993   3rd Qu.:70.85  
 Australia  :  12                  Max.   :2007   Max.   :82.60  
 (Other)    :1632                                                
      pop              gdpPercap       
 Min.   :6.001e+04   Min.   :   241.2  
 1st Qu.:2.794e+06   1st Qu.:  1202.1  
 Median :7.024e+06   Median :  3531.8  
 Mean   :2.960e+07   Mean   :  7215.3  
 3rd Qu.:1.959e+07   3rd Qu.:  9325.5  
 Max.   :1.319e+09   Max.   :113523.1  
                                       

1.9.3 Questions

  • List questions based on this data.
  • What do you want to see?
  • What kind of chart do you want to construct?

Review

  • R on R Studio/Posit Cloud (RStudio Cloud)
  • Three ways to run codes
    1. Console
    2. R Script
    3. Code Chunk in R Notebook
  • Packages
    1. tidyverse
    2. rmarkdown
    3. gapminder

EDA (A diagram from R4DS by H.W. and G.G.)

EDA from r4ds

Today: R Markdown and dplyr

2 Exploratory Data Analysis II

2.1 R Markdown

What is R Markdown: https://vimeo.com/178485416

  • Code Chunks
  • Text
  • YAML Metadata

2.1.1 What is R Markdown and R Notebook

R Markdown provides an authoring framework for data science. You can use a single R Markdown file to both

  • save and execute code
  • generate high quality reports that can be shared with an audience

R Notebooks are an implementation of Literate Programming that allows for direct interaction with R while producing a reproducible document with publication-quality output.

An R Notebook is an R Markdown document with chunks that can be executed independently and interactively, with output visible immediately beneath the input.

(Reference: R Markdown: The Definitive Guide, 3.2 Notebook)


2.1.1.1 Two Goodies

  • Important: Implementation of Reproducible Research and Literate Programming

  • Useful to Render into Various Formats: R Notebook (HTML), R Markdown (HTML), PDF, MS Word, MS Powerpoint, Ioslides Presentation (HTML), Slidy Presentation (HTML), Beamer Presentation (PDF), etc.


2.1.2 Reproducible Research and Literate Programming

2.1.2.1 Literate Programming by D. Knuth

Literate programming is an approach to programming introduced by Donald Knuth in which a program is given as an explanation of the program logic in a natural language, such as English, interspersed with snippets of macros and traditional source code, from which a compilable source code can be generated

2.1.2.2 D. Knuth

Let us change our traditional attitude to the construction of programs: Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.


2.1.2.3 Reproducible Research - Quote from a Coursera Course

Reproducible research is the idea that data analyses, and more generally, scientific claims, are published with their data and software code so that others may verify the findings and build upon them. The need for reproducibility is increasing dramatically as data analyses become more complex, involving larger datasets and more sophisticated computations. Reproducibility allows for people to focus on the actual content of a data analysis, rather than on superficial details reported in a written summary. In addition, reproducibility makes an analysis more useful to others because the data and code that actually conducted the analysis are available.


2.1.2.4 R Markdown workflow, R for Data Science

R Markdown is also important because it so tightly integrates prose and code. This makes it a great analysis notebook because it lets you develop code and record your thoughts. It:

  • Records what you did and why you did it. Regardless of how great your memory is, if you don’t record what you do, there will come a time when you have forgotten important details. Write them down so you don’t forget!

  • Supports rigorous thinking. You are more likely to come up with a strong analysis if you record your thoughts as you go, and continue to reflect on them. This also saves you time when you eventually write up your analysis to share with others.

  • Helps others understand your work. It is rare to do data analysis by yourself, and you’ll often be working as part of a team. A lab notebook helps you share why you did it with your colleagues or lab mates.


2.1.2.5 Records of EDA and Communication

  1. Memo on a scratch paper: R Scripts
  2. Record on a notebook: R Notebook (an R Markdown format)
  3. Short paper or a digital communication: R Notebook
  4. Paper or a report: R Markdown (html, pdf, MS Word, etc.)
  5. Presentation (html, pdf, MS Powerpoint, etc.)
  6. Publication of a Book

2.1.3 Let’s Get Started

  1. Start R Studio - Update R Studio if old
  2. Create a Project
  3. Tool > Install Packages rmarkdown
    • Or on Console: install.packages("rmarkdown")
  4. Tool > Install Packages tinytex (for pdf generation)
    • Alternatively, install.packages('tinytex')
    • If TeX is not installed: tinytex::install_tinytex() # install TinyTeX
      • If you are not sure, please check on Terminal in the left below pane:
        • which latex, which mktexlsr
  5. Let’s try!
    1. File > New File > R Notebook
    2. Save with a file name, say, test-notebook
    3. Preview by [Preview] button
    4. Run Code Chunk plot(cars) and then Preview again.
    5. Knit PDF, Word (and HTML)

2.1.4 Templates

2.1.4.1 RNotebook_Template

Template to submit your assignment of this course: RNotebook_Template.nb.html

title: "Title of R Notebook"
author: "ID and Your Name"
date: "2023-01-26" 
output:
  html_notebook: null
2.1.4.1.1 YAML
  • Change the title
  • Write ID and your name
  • Date is auto-generated and inserted. If you wish, you can replace “2023-01-26” by your favorite date style.

2.1.4.1.2 Code Chunk
  • When you execute or run a code within the notebook, the results appear beneath the code.
  • Try executing this chunk by clicking the Run button, a triangle pointing right, within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter (Win) or Cmd+Shift+Enter (Mac).
  • Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Option+I (Win) or Cmd+Option+I (Mac).
  • When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K (Win) or Cmd+Shift+K (Mac) to preview the HTML file).
  • The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

2.1.4.2 Testing R Markdown Formats

Various Output Formats: test-rmarkdown.nb.html

title: "Testing R Markdown Formats"
author: "DS-SL"
date: "2023-01-26"
output:
  html_notebook:
    number_sections: yes
  pdf_document: 
    number_sections: yes
  html_document:
    df_print: paged
    number_sections: yes
  word_document: 
    number_sections: yes
  powerpoint_presentation: default
  ioslides_presentation:
    widescreen: yes
    smaller: yes
  slidy_presentation: default
  beamer_presentation: default

2.1.4.3 Comments on Presentation Formats and Options

  • For slides, a new slide starts at ##, the second-level heading.
  • --- is page break for presentation formats.
  • For Word and Powerpoint, you can add your template. See the documents in References
    • Use R Markdown to create a Word document [similar for PowerPoint]
    • Save the rendered Word file as: ref-doc-style.docx
    • Edit the styles of the file ref-doc-style.docx
    • Add ref-doc-style.docx as reference_doc in YAML with indention as below
  word_document: 
    number_sections: yes
    reference_doc: ref-doc-style.docx
  powerpoint_presentation: 
    reference_doc: ref-ppt-style.pptx
  • You can use Output Options at the bottom of the gear icon next to Preview/knit button.

2.1.5 Markdown Language – or use WYSIWYG editor

  • Headers: #, ##, ###, ####
  • Lists: 1. 2. , *
  • Links: linked phrase
  • Images: ![alt text](figures/filename.jpg)
  • Block quotes” > (block)
  •   equations: e.g. $\frac{a}{b}$ for \(\frac{a}{b}\)
  • Horizontal rules: Three or more asterisks or dashes (*** or - - - )
  • Tables
  • Footnotes
  • Bibliographies and Citations
  • Slide breaks
  • Italicized text by _italic_, Bold text by **bold**
  • Superscripts, Subscripts, Strikethrough text

2.1.5.1 Visual R Markdown

R Studio introduced Visual Editor towards the end of 2021. It seems to be stable but it is not perfect to go back and forth from the original editor using tags. I always use the original editor and I am confident on all the functions of it but I do not have much experience on Visual Editor. [My Note in QALL401 2021]


2.1.6 References

2.2 Data Transforamtion with dplyr

2.2.1 dplyr Overview

dplyr is a grammar of data manipulation, providing a consistent set of verbs that help you solve the most common data manipulation challenges:

  • select() picks variables based on their names.
  • filter() picks cases based on their values.
  • mutate() adds new variables that are functions of existing variables
  • summarise() reduces multiple values down to a single summary.
  • arrange() changes the ordering of the rows.
  • group_by() takes an existing tbl and converts it into a grouped tbl.

You can learn more about them in vignette(“dplyr”). As well as these single-table verbs, dplyr also provides a variety of two-table verbs, which you can learn about in vignette(“two-table”).

If you are new to dplyr, the best place to start is the data transformation chapter in R for data science.


2.2.2 select: Subset columns using their names and types

Helper Function Use Example
- Columns except select(babynames, -prop)
: Columns between (inclusive) select(babynames, year:n)
contains() Columns that contains a string select(babynames, contains(“n”))
ends_with() Columns that ends with a string select(babynames, ends_with(“n”))
matches() Columns that matches a regex select(babynames, matches(“n”))
num_range() Columns with a numerical suffix in the range Not applicable with babynames
one_of() Columns whose name appear in the given set select(babynames, one_of(c(“sex”, “gender”)))
starts_with() Columns that starts with a string select(babynames, starts_with(“n”))

2.2.3 filter: Subset rows using column values

Logical operator tests Example
> Is x greater than y? x > y
>= Is x greater than or equal to y? x >= y
< Is x less than y? x < y
<= Is x less than or equal to y? x <= y
== Is x equal to y? x == y
!= Is x not equal to y? x != y
is.na() Is x an NA? is.na(x)
!is.na() Is x not an NA? !is.na(x)

2.2.4 arrange and Pipe %>%

  • arrange() orders the rows of a data frame by the values of selected columns.

Unlike other dplyr verbs, arrange() largely ignores grouping; you need to explicitly mention grouping variables (`or use .by_group = TRUE) in order to group by them, and functions of variables are evaluated once per data frame, not once per group.

  • pipes in R for Data Science.

2.2.5 mutate

  • Create, modify, and delete columns

  • Useful mutate functions

    • +, -, log(), etc., for their usual mathematical meanings

    • lead(), lag()

    • dense_rank(), min_rank(), percent_rank(), row_number(), cume_dist(), ntile()

    • cumsum(), cummean(), cummin(), cummax(), cumany(), cumall()

    • na_if(), coalesce()### group_by() and summarise()


2.2.6 group_by


2.2.7 summarise or summarize

2.2.7.1 Summary functions

So far our summarise() examples have relied on sum(), max(), and mean(). But you can use any function in summarise() so long as it meets one criteria: the function must take a vector of values as input and return a single value as output. Functions that do this are known as summary functions and they are common in the field of descriptive statistics. Some of the most useful summary functions include:

  1. Measures of location - mean(x), median(x), quantile(x, 0.25), min(x), and max(x)
  2. Measures of spread - sd(x), var(x), IQR(x), and mad(x)
  3. Measures of position - first(x), nth(x, 2), and last(x)
  4. Counts - n_distinct(x) and n(), which takes no arguments, and returns the size of the current group or data frame.
  5. Counts and proportions of logical values - sum(!is.na(x)), which counts the number of TRUEs returned by a logical test; mean(y == 0), which returns the proportion of TRUEs returned by a logical test.
  • if_else(), recode(), case_when()

2.2.8 Learn dplyr by Examples

2.2.8.1 Data iris

iris

summary(iris)
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
       Species  
 setosa    :50  
 versicolor:50  
 virginica :50  
                
                
                

2.2.8.2 select 1 - columns 1, 2, 5

select(iris, c(1,2,5))

2.2.8.3 select 2 - except Species

select(iris, -Species)

2.2.8.4 select 3 - change column names

select(iris, sl = Sepal.Length, sw = Sepal.Width, sp = Species)

2.2.8.5 filter - by names

filter(iris, Species == "virginica")

2.2.8.6 arrange - ascending and descending order

arrange(iris, Sepal.Length, desc(Sepal.Width))

2.2.8.7 mutate - rank

iris %>% mutate(sl_rank = min_rank(Sepal.Length)) %>% arrange(sl_rank)

2.2.8.8 group_by and summarize

iris %>% 
  group_by(Species) %>% 
  summarize(sl = mean(Sepal.Length), sw = mean(Sepal.Width), 
  pl = mean(Petal.Length), pw = mean(Petal.Width))
  • mean: mean() or mean(x, na.rm = TRUE) - arithmetic mean (average)
  • median: median() or median(x, na.rm = TRUE) - mid value

For more examples see

dplr_iris

2.2.9 References of dplyr

2.2.9.1 RStudio Primers: See References in Moodle at the bottom

  1. The Basics – r4ds: Explore, I
  1. Work with Datar4ds: Wrangle, I
  • Working with Tibbles
  • Isolating Data with dplyr
  • Deriving Information with dplyr
  1. Visualize Data – r4ds: Explore, II
  2. Tidy Your Data – r4ds: Wrangle, II
  3. Iterate – r4ds: Program
  4. Write Functions – r4ds: Program

2.2.10 Learn dplyr by Examples II - gapminder

2.2.10.1 ggplot2 Overview

ggplot2 is a system for declaratively creating graphics, based on The Grammar of Graphics. You provide the data, tell ggplot2 how to map variables to aesthetics, what graphical primitives to use, and it takes care of the details.

Examples

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy))
ggplot(data = mpg) + 
  geom_boxplot(mapping = aes(x = class, y = hwy))

Template

ggplot(data = <DATA>) + 
  <GEOM_FUNCTION>(mapping = aes(<MAPPINGS>))

2.2.10.2 Gapminder and R Package gapminder

Gapminder was founded by Ola Rosling, Anna Rosling Rönnlund, and Hans Rosling


library(tidyverse)
library(gapminder)
library(WDI)

2.2.10.3 R Package gapminder data

df <- gapminder
df

glimpse(df)
Rows: 1,704
Columns: 6
$ country   <fct> "Afghanistan", "Afghanistan", "Afghanistan", "A…
$ continent <fct> Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia,…
$ year      <int> 1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987,…
$ lifeExp   <dbl> 28.801, 30.332, 31.997, 34.020, 36.088, 38.438,…
$ pop       <int> 8425333, 9240934, 10267083, 11537966, 13079460,…
$ gdpPercap <dbl> 779.4453, 820.8530, 853.1007, 836.1971, 739.981…

summary(df)
        country        continent        year         lifeExp     
 Afghanistan:  12   Africa  :624   Min.   :1952   Min.   :23.60  
 Albania    :  12   Americas:300   1st Qu.:1966   1st Qu.:48.20  
 Algeria    :  12   Asia    :396   Median :1980   Median :60.71  
 Angola     :  12   Europe  :360   Mean   :1980   Mean   :59.47  
 Argentina  :  12   Oceania : 24   3rd Qu.:1993   3rd Qu.:70.85  
 Australia  :  12                  Max.   :2007   Max.   :82.60  
 (Other)    :1632                                                
      pop              gdpPercap       
 Min.   :6.001e+04   Min.   :   241.2  
 1st Qu.:2.794e+06   1st Qu.:  1202.1  
 Median :7.024e+06   Median :  3531.8  
 Mean   :2.960e+07   Mean   :  7215.3  
 3rd Qu.:1.959e+07   3rd Qu.:  9325.5  
 Max.   :1.319e+09   Max.   :113523.1  
                                       

2.2.10.4 Tidyverse::ggplot

2.2.10.4.1 First Try - with failures
ggplot(df, aes(x = year, y = lifeExp)) + geom_point()


ggplot(df, aes(x = year, y = lifeExp)) + geom_line()


ggplot(df, aes(x = year, y = lifeExp)) + geom_boxplot()


typeof(pull(df, year)) # same as typeof(df$year)
[1] "integer"

ggplot(df, aes(y = lifeExp, group = year)) + geom_boxplot()


2.2.10.4.2 Box Plot
ggplot(df, aes(x = as_factor(year), y = lifeExp)) + geom_boxplot()


2.2.10.5 Applications of dplyr

2.2.10.5.1 filter
df %>% filter(country == "Afghanistan") %>%
  ggplot(aes(x = year, y = lifeExp)) + geom_line()


df %>% filter(country %in% c("Afghanistan", "Japan")) %>%
  ggplot(aes(x = year, y = lifeExp, color = country)) + geom_line()


df %>% distinct(country) %>% pull()
  [1] Afghanistan              Albania                 
  [3] Algeria                  Angola                  
  [5] Argentina                Australia               
  [7] Austria                  Bahrain                 
  [9] Bangladesh               Belgium                 
 [11] Benin                    Bolivia                 
 [13] Bosnia and Herzegovina   Botswana                
 [15] Brazil                   Bulgaria                
 [17] Burkina Faso             Burundi                 
 [19] Cambodia                 Cameroon                
 [21] Canada                   Central African Republic
 [23] Chad                     Chile                   
 [25] China                    Colombia                
 [27] Comoros                  Congo, Dem. Rep.        
 [29] Congo, Rep.              Costa Rica              
 [31] Cote d'Ivoire            Croatia                 
 [33] Cuba                     Czech Republic          
 [35] Denmark                  Djibouti                
 [37] Dominican Republic       Ecuador                 
 [39] Egypt                    El Salvador             
 [41] Equatorial Guinea        Eritrea                 
 [43] Ethiopia                 Finland                 
 [45] France                   Gabon                   
 [47] Gambia                   Germany                 
 [49] Ghana                    Greece                  
 [51] Guatemala                Guinea                  
 [53] Guinea-Bissau            Haiti                   
 [55] Honduras                 Hong Kong, China        
 [57] Hungary                  Iceland                 
 [59] India                    Indonesia               
 [61] Iran                     Iraq                    
 [63] Ireland                  Israel                  
 [65] Italy                    Jamaica                 
 [67] Japan                    Jordan                  
 [69] Kenya                    Korea, Dem. Rep.        
 [71] Korea, Rep.              Kuwait                  
 [73] Lebanon                  Lesotho                 
 [75] Liberia                  Libya                   
 [77] Madagascar               Malawi                  
 [79] Malaysia                 Mali                    
 [81] Mauritania               Mauritius               
 [83] Mexico                   Mongolia                
 [85] Montenegro               Morocco                 
 [87] Mozambique               Myanmar                 
 [89] Namibia                  Nepal                   
 [91] Netherlands              New Zealand             
 [93] Nicaragua                Niger                   
 [95] Nigeria                  Norway                  
 [97] Oman                     Pakistan                
 [99] Panama                   Paraguay                
[101] Peru                     Philippines             
[103] Poland                   Portugal                
[105] Puerto Rico              Reunion                 
[107] Romania                  Rwanda                  
[109] Sao Tome and Principe    Saudi Arabia            
[111] Senegal                  Serbia                  
[113] Sierra Leone             Singapore               
[115] Slovak Republic          Slovenia                
[117] Somalia                  South Africa            
[119] Spain                    Sri Lanka               
[121] Sudan                    Swaziland               
[123] Sweden                   Switzerland             
[125] Syria                    Taiwan                  
[127] Tanzania                 Thailand                
[129] Togo                     Trinidad and Tobago     
[131] Tunisia                  Turkey                  
[133] Uganda                   United Kingdom          
[135] United States            Uruguay                 
[137] Venezuela                Vietnam                 
[139] West Bank and Gaza       Yemen, Rep.             
[141] Zambia                   Zimbabwe                
142 Levels: Afghanistan Albania Algeria Angola ... Zimbabwe

df %>% filter(country %in% c("Brazil", "Russia", "India", "China")) %>%
  ggplot(aes(x = year, y = lifeExp, color = country)) + geom_line()

Russian data is missing.


2.2.11 Exercises

  1. Change lifeExp to pop and gdpPercap and do the same.
  2. Choose ASEAN countries and do the similar investigations.
  • Brunei, Cambodia, Indonesia, Laos, Malaysia, Myanmar, Philippines, Singapore.
  1. Choose several countries by yourself and do the similar investigations.

2.2.12 group_by and summarize

Let us use the variable continent and summarize the data.

df_lifeExp <- df %>% group_by(continent, year) %>% 
  summarize(mean_lifeExp = mean(lifeExp), median_lifeExp = median(lifeExp), max_lifeExp = max(lifeExp), min_lifeExp = min(lifeExp), .groups = "keep")

df_lifeExp

df %>% filter(year %in% c(1952, 1987, 2007)) %>%
  ggplot(aes(x=as_factor(year), y = lifeExp, fill = continent)) +
  geom_boxplot()


df_lifeExp %>% ggplot(aes(x = year, y = mean_lifeExp, color = continent)) +
  geom_line()


df_lifeExp %>% ggplot(aes(x = year, y = mean_lifeExp, color = continent, linetype = continent)) +
  geom_line()


df_lifeExp %>% ggplot() +
  geom_line(aes(x = year, y = mean_lifeExp, color = continent)) + 
  geom_line(aes(x = year, y = median_lifeExp, linetype = continent))

2.3 The Week Three Assignment (in Moodle)

R Markdown and dplyr

  • Create an R Notebook of a Data Analysis containing the following and submit the rendered HTML file (eg. a2_123456.nb.html)
    1. create an R Notebook using the R Notebook Template in Moodle, save as a2_123456.Rmd,
    2. write your name and ID and the contents,
    3. run each code block,
    4. preview to create a2_123456.nb.html,
    5. submit a2_123456.nb.html to Moodle.
  1. Pick data from the built-in datasets besides cars. (library(help = "datasets") or go to the site The R Datasets Package)

    • Information of the data: Name, Description, Usage, Format, Source, References (Hint: ?cars)
    • Use head(), str(), …, and create at least one chart using ggplot2 - Code Chunk.
      • Don’t forget to add library(tidyverse) in the first code chunk.
    • An observation of the chart - in your own words.

  1. Load gapminder by library(gapminder).

    • Choose pop or gdpPercap, or both, one country in the data, a group of countries in the data.
    • Create charts using ggplot2 with geom_line and the variables and countries chosen in 1. (See examples of the charts for lifeExp.)
    • Study the data as you like.
    • Observations and difficulties encountered.

Due: 2023-01-09 23:59:00. Submit your R Notebook file in Moodle (The Second Assignment). Due on Monday!


2.3.1 Original Data? WDI?

gapminder

2.3.1.1 WDI

  • SP.DYN.LE00.IN: Life expectancy at birth, total (years)
  • NY.GDP.PCAP.KD: GDP per capita (constant 2015 US$)
  • SP.POP.TOTL: Population, total
df_wdi <- WDI(
  country = "all", 
  indicator = c(lifeExp = "SP.DYN.LE00.IN", pop = "SP.POP.TOTL", gdpPercap = "NY.GDP.PCAP.KD")
)
source("~/Documents/_class/gsclasses/2022/da4r2022_note/docs/eda5.Rmd")
Error in source("~/Documents/_class/gsclasses/2022/da4r2022_note/docs/eda5.Rmd") : 
  ~/Documents/_class/gsclasses/2022/da4r2022_note/docs/eda5.Rmd:24:4: unexpected numeric constant
23: 
24: 1. 2022.12
       ^

df_wdi

df_wdi_extra <- WDI(
  country = "all", 
  indicator = c(lifeExp = "SP.DYN.LE00.IN", pop = "SP.POP.TOTL", gdpPercap = "NY.GDP.PCAP.KD"), 
  extra = TRUE
)

df_wdi_extra

3 Exploratory Data Analysis III

3.1 Importing Public Data, WDI

3.1.1 Reviews and Previews

library(tidyverse)
library(gapminder)
library(maps)
library(WDI)
library(readxl)
library(ggrepel)
  • We have used tidyverse and gapminder already.
  • If you have not installed WDI, install it.
  • We will not use ggrepel but if you want to use it, install it.
  • maps and readxl are bundled in tidyverse but need to be attached by library.

3.1.1.1 Gapminder Package Data

df <- gapminder
df

3.1.1.2 gdpPercap of ASEAN countries

asean <- c("Brunei", "Cambodia", "Laos", "Myanmar", 
           "Philippines", "Indonesia", "Malaysia", "Singapore")
df %>% filter(country %in% asean) %>%
  ggplot(aes(x = year, y = gdpPercap, col = country)) + geom_line()


df %>% filter(country %in% asean) %>%
  ggplot(aes(x = gdpPercap, y = lifeExp, col = country)) + geom_point()


df %>% filter(country %in% asean) %>%
  ggplot(aes(x = gdpPercap, y = lifeExp, col = country)) + 
  geom_point() + coord_trans(x = "log10", y = "identity")

\(\log_{10}{100}\) = 2, \(\log_{10}{1000}\) = 3, \(\log_{10}{10000}\) = 4


library(ggrepel)
df2007 <- df %>% filter(country %in% asean, year == 2007)
df %>% filter(country %in% asean) %>%
  ggplot(aes(x = gdpPercap, y = lifeExp, col = country))+ 
  geom_line() + geom_label_repel(data = df2007, aes(label = country)) + geom_point()  +
  coord_trans(x = "log10", y = "identity") +
  theme(axis.text.x = element_text(angle = 90, vjust = 1, hjust=1), legend.position = "none") +
  labs(title = "Life Expectancy vs GDP Per Capita of ASEAN Countries",
       subtitle = "Data: gapminder package", x = "GDP per Capita", y = "Life Expectancy")



3.1.1.3 World Bank: World Development Indicators (WDI)

  • SP.DYN.LE00.IN: Life expectancy at birth, total (years)
  • NY.GDP.PCAP.KD: GDP per capita (constant 2015 US$)
  • SP.POP.TOTL: Population, total
df_wdi <- WDI(
  country = "all", 
  indicator = c(lifeExp = "SP.DYN.LE00.IN", pop = "SP.POP.TOTL", gdpPercap = "NY.GDP.PCAP.KD")
)

df_wdi

df_wdi_extra <- WDI(
  country = "all", 
  indicator = c(lifeExp = "SP.DYN.LE00.IN", pop = "SP.POP.TOTL", gdpPercap = "NY.GDP.PCAP.KD"), 
  extra = TRUE
)

df_wdi_extra

3.1.2 Exploratory Data Analysis

3.1.2.1 What is EDA (Posit Primers: Visualise Data)

  1. EDA is an iterative cycle that helps you understand what your data says. When you do EDA, you:

  2. Generate questions about your data

  3. Search for answers by visualising, transforming, and/or modeling your data

Use what you learn to refine your questions and/or generate new questions

EDA is an important part of any data analysis. You can use EDA to make discoveries about the world; or you can use EDA to ensure the quality of your data, asking questions about whether the data meets your standards or not.


3.1.3 Open and Public Data, World Bank

3.1.3.1 Open Government Data Toolkit: Open Data Defined

The term Open Data has a very precise meaning. Data or content is open if anyone is free to use, re-use or redistribute it, subject at most to measures that preserve provenance and openness.

  1. The data must be legally open, which means they must be placed in the public domain or under liberal terms of use with minimal restrictions.
  2. The data must be technically open, which means they must be published in electronic formats that are machine readable and non-proprietary, so that anyone can access and use the data using common, freely available software tools. Data must also be publicly available and accessible on a public server, without password or firewall restrictions. To make Open Data easier to find, most organizations create and manage Open Data catalogs.

3.1.4 World Bank: WDI - World Development Indicaters

  • World Bank: https://www.worldbank.org
  • Who we are:
    • To end extreme poverty: By reducing the share of the global population that lives in extreme poverty to 3 percent by 2030.
    • To promote shared prosperity: By increasing the incomes of the poorest 40 percent of people in every country.
  • World Bank Open Data: https://data.worldbank.org
    • Data Bank, World Development Indicators, etc.
  • World Development Indicators (WDI) : the World Bank’s premier compilation of cross-country comparable data on development; 1400 time series indicators
    • Themes: Poverty and Inequality, People, Environment, Economy, States and Markets, Global Links
    • Open Data & DataBank: Explore data, Query database
    • Bulk Download: Excel, CSV
    • API Documentation

3.1.5 R Package WDI

  • WDI: World Development Indicators and Other World Bank Data
  • Search and download data from over 40 databases hosted by the World Bank, including the World Development Indicators (‘WDI’), International Debt Statistics, Doing Business, Human Capital Index, and Sub-national Poverty indicators.
  • Version: 2.7.4
  • Materials: README - usage
    • NEWS - version history
  • Published: 2021-04-06
  • README: https://cran.r-project.org/web/packages/WDI/readme/README.html
  • Reference manual: WDI.pdf

3.1.6 Function WDI

  • Usage
WDI(country = "all",
    indicator = "NY.GDP.PCAP.KD",
    start = 1960,
    end = 2020,
    extra = FALSE,
    cache = NULL)
  • Arguments See Help!
    • country: Vector of countries (ISO-2 character codes, e.g. “BR”, “US”, “CA”, or “all”)
    • indicator: If you supply a named vector, the indicators will be automatically renamed: c('women_private_sector' = 'BI.PWK.PRVS.FE.ZS')

3.1.7 Function WDIsearch

library(WDI)
WDIsearch(string = "NY.GDP.PCAP.KD", 
          field = "indicator", cache = NULL)

WDIsearch(string = "population", 
          field = "name", short=FALSE, cache = NULL)

WDIsearch(string = "NY.GDP.PCAP.KD", 
  field = "indicator", short = FALSE, cache = NULL)
WDIsearch(string = "gdp", 
  field = "name", short = TRUE, cache = NULL) 

3.1.8 Bulk Downloads at WDI site

WDIbulk downloads the zip file of Bulk Downloads in WDI site , it is a list containing 6 data frames: Data, Country, Series, Country-Series, Series-Time, FootNote.


3.1.9 WDIcache

Download an updated list of available WDI indicators from the World Bank website. Returns a list for use in the WDIsearch function.

wdi_cache <- WDIcache()

Downloading all series information from the World Bank website can take time. The WDI package ships with a local data object with information on all the series available on 2012-06-18. You can update this database by retrieving a new list using WDIcache, and then feeding the resulting object to WDIsearch via the cache argument.


wdi_cache

3.1.10 WDI_data

List of 2 data frames

The first character matrix includes a full list of WDI series. This list is updated semi-regularly. Users can refresh the list manually using the ‘WDIcache()’ function and search in the updated list using the ‘cache’ argument.

WDI_data$country  %>% filter(country == "Japan")

WDIsearch(string = "gdp", 
  field = "name", short = FALSE, cache = NULL) #cache = wdi_cache

3.1.11 World Development Indicators - Summary

Find indicators:

  1. WDIsearch(string = "gdp", field = "name", short = FALSE, cache = NULL)
  • WDIsearch(string = "gdp", field = "name", short = FALSE, cache = wdi_cache)
  • WDIsearch(string = "NY.GDP.PCAP.KD", field = "indicator", short = FALSE, cache = NULL)
  1. WDI: Data Themes
  2. Browse by Indicators: https://data.worldbank.org/indicator
    • Featured Indicators or All Indicators
    • Obtain the indicator from the detail or the URL

3.1.11.1 Example: CO2 emissions (metric tons per capita)

WDIsearch(string = "EN.ATM.CO2E.PC", field = "indicator", 
          short = FALSE, cache = NULL) #cache = wdi_cache
WDIsearch(string = "EN.ATM.CO2E.PC", field = "indicator", 
          short = FALSE, cache = NULL) %>% pull(description) #cache = wdi_cache
[1] "Carbon dioxide emissions are those stemming from the burning of fossil fuels and the manufacture of cement. They include carbon dioxide produced during consumption of solid, liquid, and gas fuels and gas flaring."
  • Source: Climate Watch. 2020. GHG Emissions. Washington, DC: World Resources Institute. Available at: climatewatchdata.org/ghg-emissions. See SP.POP.TOTL for the denominator’s source.

co2pcap <- WDI(country = "all", indicator = "EN.ATM.CO2E.PC", start = 1960, end = NULL, extra = TRUE, cache = NULL) #cache = wdi_cache
co2pcap

write_csv(co2pcap, "data/co2pcap.csv")

co2pcap %>% filter(country %in% c("World", "Japan", "United States", "China")) %>%
  ggplot(aes(x = year, y = EN.ATM.CO2E.PC, color = country)) + 
  geom_line()


co2pcap %>% filter(!is.na(EN.ATM.CO2E.PC)) %>% pull(year) %>% summary()
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1990    1997    2005    2005    2012    2019 

co2pcap %>% 
  filter(country %in% c("World", "Japan", "United States", "China"), year %in% 1990:2019) %>%
  ggplot(aes(x = year, y = EN.ATM.CO2E.PC, color = country)) + 
  geom_line()


co2pcap %>% 
  filter(income != "Aggregates", year == 2019) %>%
  ggplot(aes(x = income, y = EN.ATM.CO2E.PC, fill = income)) + 
  geom_boxplot()


co2pcap %>% 
  filter(income != "Aggregates", year == 2019, !is.na(EN.ATM.CO2E.PC)) %>%
  ggplot(aes(x = income, y = EN.ATM.CO2E.PC, fill = income)) + 
  geom_boxplot()


co2pcap %>% 
  filter(income != "Aggregates", year == 2019, !is.na(EN.ATM.CO2E.PC)) %>%
  group_by(income) %>%
  summarize(min = min(EN.ATM.CO2E.PC), med = median(EN.ATM.CO2E.PC), max = max(EN.ATM.CO2E.PC), IQR = IQR(EN.ATM.CO2E.PC), n = n())

co2pcap %>% 
  filter(income != "Aggregates", year == 2019, !is.na(EN.ATM.CO2E.PC)) %>%
  filter(!income %in% c("High income", "Low income", "Lower middle income", "Upper middle income"))
co2pcap %>% 
  filter(income != "Aggregates", year == 2019) %>%
  filter(income == "Not classified")

co2pcap %>% 
  filter(income != "Aggregates", year == 2019) %>%
  ggplot(aes(map_id = country)) + 
  geom_map(aes(fill = income), map = world_map) + expand_limits(x = world_map$long, y = world_map$lat) +
  labs(title = "Income Levels in 2019")


co2pcap %>% distinct(country)

world_map %>% distinct(region)

world_map0 <- world_map %>% 
  mutate(region = case_when(region == "Macedonia" ~ "North Macedonia",
                            region == "Ivory Coast"  ~ "Cote d'Ivoire",
                            region == "Democratic Republic of the Congo"  ~ "Congo, Dem. Rep.",
                            region == "Republic of Congo" ~  "Congo, Rep.",
                            region == "UK" ~  "United Kingdom",
                            region == "USA" ~  "United States",
                            region == "Laos" ~  "Lao PDR",
                            region == "Slovakia" ~  "Slovak Republic",
                            region == "Saint Lucia" ~  "St. Lucia",
                            region == "Kyrgyzstan"  ~  "Kyrgyz Republic",
                            region == "Micronesia" ~ "Micronesia, Fed. Sts.",
                            region == "Swaziland"  ~ "Eswatini", 
                            region == "Virgin Islands"  ~ "Virgin Islands (U.S.)", 
                            region == "Russia" ~ "Russian Federation", 
                            region == "Egypt" ~ "Egypt, Arab Rep.",
                            region == "South Korea" ~ "Korea, Rep.",
                            region == "North Korea" ~ "Korea, Dem. People's Rep.",
                            region == "Iran" ~ "Iran, Islamic Rep.",
                            region == "Brunei" ~ "Brunei Darussalam",
                            region == "Venezuela" ~ "Venezuela, RB",
                            region == "Yemen" ~ "Yemen, Rep.",
                            region == "Bahamas" ~ "Bahamas, The",
                            region == "Syria" ~ "Syrian Arab Republic",
                            region == "Turkey" ~ "Turkiye",
                            region == "Cape Verde" ~ "Cabo Verde",
                            region == "Gambia" ~ "Gambia, The",
                            region == "Czech Republic" ~ "Czechia",
                            TRUE ~ region))

write_csv(world_map0, "data/world_map0.csv")
map0_url <- "https://icu-hsuzuki.github.io/da4r2022_note/data/world_map0.csv"
world_map0 <- read_csv(map0_url)

co2pcap %>% filter(income != "Aggregates", year == 2019) %>% 
  anti_join(world_map0, by = c("country"="region"))

world_map0 %>% anti_join(co2pcap, by = c("region"="country")) %>% distinct(region) %>% arrange(region)

world_map0 %>% left_join(iso3166, by = c("region" = "ISOname")) %>%
  filter(is.na(a2)) %>% distinct(region)

3.2 Data Visualization and `ggplot2’

3.2.1 Learning Resouces

  • Posit Primers:
    • Visualize Data: Learn how to use ggplot2 to make any type of plot with your data. Then learn the best ways to visualize patterns within values and relationships between variables.
  • r4ds: Data Visualization

3.2.2 Exploratory Data Analysis

3.2.2.1 What is EDA?

EDA is an iterative cycle that helps you understand what your data says. When you do EDA, you:

  1. Generate questions about your data

  2. Search for answers by visualising, transforming, and/or modeling your data

  3. Use what you learn to refine your questions and/or generate new questions

EDA is an important part of any data analysis. You can use EDA to make discoveries about the world; or you can use EDA to ensure the quality of your data, asking questions about whether the data meets your standards or not.


3.2.2.2 Two useful questions

There is no rule about which questions you should ask to guide your research. However, two types of questions will always be useful for making discoveries within your data. You can loosely word these questions as:

  1. What type of variation occurs within my variables?
  2. What type of covariation occurs between my variables?

The rest of this tutorial will look at these two questions. To make the discussion easier, let’s define some terms…


3.2.3 Data Visualization

3.2.4 ggplot2 Basics

visualization


3.2.5 Example: World Inequility Report - WIR2022

library(readxl)
url_summary <- "https://wir2022.wid.world/www-site/uploads/2022/03/WIR2022TablesFigures-Summary.xlsx"
download.file(url = url_summary, destfile = "data/WIR2022s.xlsx") 
excel_sheets("data/WIR2022s.xlsx")

3.2.6 F14: Global carbon inequality, 2019. Group contribution to world emissions (%)

Note that the sheet name of F14 has period at the end.

df_f14 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F14.")
Error: `path` does not exist: ‘data/WIR2022s.xlsx’
  • \n for line break in the title.

3.2.6.1 Categorical vs Continuous Value

df_f14 %>% 
  ggplot(aes(x = Group, y = Share)) +
  geom_col()

df_f14 %>% 
  ggplot(aes(x = Group, y = Share)) +
  geom_col(width = 0.5, fill = scales::hue_pal()(1)[1]) + 
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 14. Global carbon inequality, \n2019 Group contribution to world emissions (%)", 
       x = "", y = "Share of world emissions (%)")

3.2.6.2 Memo

  • width = 0.5: width of bars
  • fill = scales::hue_pal()(1)[1]): hue scale
  • scale_y_continuous(labels = scales::percent_format(accuracy = 1)): percent format
    • if accuracy = 0.1, we have 10.0% etc.
  • labs(title = "Figure 14. Global carbon inequality, \n2019 Group contribution to world emissions (%)", x = "", y = "Share of world emissions (%)")
    • title = ““: \n is for line feed
    • x, y: labels of x-axis and y-axis

3.2.7 F12: Female share in global labor incomes, 1990-2020

df_f12 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F12")
df_f12

df_f12 %>% 
  select(year = "Data needs to be updated", value = ...2) %>%
  filter(!is.na(year)) %>%
  ggplot(aes(x = year, y = value)) +
  geom_col(width = 0.5, fill = scales::hue_pal()(2)[2])

df_f12 %>% 
  select(year = "Data needs to be updated", value = ...2) %>%
  filter(!is.na(year)) %>%
  ggplot(aes(x = year, y = value)) +
  geom_col(width = 0.5, fill = scales::hue_pal()(2)[2]) +
  geom_hline(yintercept = 0.5, linetype = 2, colour = scales::hue_pal()(2)[1]) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 12. Female share in global labor incomes, 1990-2020", 
        x = "", y = "") +
  annotate("text", x = 1, y = 0.48, label = "Gender parity", size = 3) +
  annotate("text", x = 5.2, y = 0.47, label = stringr::str_wrap("Women make only 35% of global labor incomes, men make the remaining  65%.", width = 40), size = 3)

3.2.8 F1: Global income and wealth inequality, 2021

df_f1 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F1")
df_f1

df_f1_rev %>%
  ggplot(aes(x = cat, y = value, fill = group)) +
  geom_col(position = "dodge")

3.2.9 References of ggplot2

3.2.9.1 RStudio Primers: See References in Moodle at the bottom

Visualize Data

  • Exploratory Data Analysis
  • Bar Charts
  • Histograms
  • Boxplots and Counts
  • Scatterplots
  • Line Plots
  • Overplotting and Big Data
  • Customize Your Plots

3.3 The Week Four Assignment (in Moodle)

WDI and ggplot2

  • Create an R Notebook of a Data Analysis containing the following and submit the rendered HTML file (eg. a3_123456.nb.html by replacing 123456 with your ID)
    1. create an R Notebook using the R Notebook Template in Moodle, save as a3_123456.Rmd,
    2. write your name and ID and the contents,
    3. run each code block,
    4. preview to create a3_123456.nb.html,
    5. submit a3_123456.nb.html to Moodle.
  1. Choose at least one indicator of WDI

    • Information of the data: Name, Indicator, Description, Source, etc.
    • Download the data with WDI
    • Explain why you chose the indicator
    • List questions you want to study

  1. Explore the data using visualization using ggplot2

    • Use a histogram (geom_histogram), boxplot (geom_boxplot), a scatter plot (geom_point), a line plot (geom_line)
    • For at least one chart, add title, and labels of axis, and add an explanation of it
  2. Observations and difficulties encountered.

Due: 2023-01-16 23:59:00. Submit your R Notebook file in Moodle (The Third Assignment). Due on Monday!

4 Exploratory Data Analysis (EDA) IV

4.1 Tidy Data

4.1.1 Reviews and Previews

4.1.2 Example: World Inequility Report - WIR2022

library(tidyverse)
library(readxl)
url_summary <- "https://wir2022.wid.world/www-site/uploads/2022/03/WIR2022TablesFigures-Summary.xlsx"
download.file(url = url_summary, destfile = "data/WIR2022s.xlsx") 
excel_sheets("data/WIR2022s.xlsx")

4.1.3 F1: Global income and wealth inequality, 2021

df_f1 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F1")
df_f1

df_f1_rev %>%
  ggplot(aes(x = cat, y = value, fill = group)) +
  geom_col(position = "dodge")

4.1.4 References of tidyr

4.1.4.1 RStudio Primers: See References in Moodle at the bottom

Tidy Your Data

  • Reshape Data
  • Separate and Unite Columns
  • Join Data Sets

4.1.5 Variables, values, and observations: Definitions

  • A variable is a quantity, quality, or property that you can measure.
  • A value is the state of a variable when you measure it. The value of a variable may change from measurement to measurement.
  • An observation or case is a set of measurements made under similar conditions (you usually make all of the measurements in an observation at the same time and on the same object). An observation will contain several values, each associated with a different variable. I’ll sometimes refer to an observation as a case or data point.
  • Tabular data is a table of values, each associated with a variable and an observation. Tabular data is tidy if each value is placed in its own cell, each variable in its own column, and each observation in its own row.
  • So far, all of the data that you’ve seen has been tidy. In real-life, most data isn’t tidy, so we’ll come back to these ideas again in Data Wrangling.

4.1.6 Tidy Data

“Data comes in many formats, but R prefers just one: tidy data.” — Garrett Grolemund

Data can come in a variety of formats, but one format is easier to use in R than the others. This format is known as tidy data. A data set is tidy if:

  1. Each variable is in its own column
  2. Each observation is in its own row
  3. Each value is in its own cell (this follows from #1 and #2)

“Tidy data sets are all alike; but every messy data set is messy in its own way.” — Hadley Wickham

“all happy families are all alike; each unhappy family is unhappy in its own way” - Tolstoy’s Anna Karenina


4.1.7 tidyr Basics

  1. Each variable is in its own column
  2. Each observation is in its own row

4.1.8 Pivot data from wide to long: pivot_longer()

pivot_longer(data, cols = <columns to pivot into longer format>,
  names_to = <name of the new character column>, # e.g. "group", "category", "class"
  values_to = <name of the column the values of cells go to>) # e.g. "value", "n"
df_f1
(df_f1_rev <- df_f1 %>% pivot_longer(-1, names_to = "group", values_to = "value"))

df_f1_rev %>% 
  ggplot(aes(x = ...1, y = value, fill = group)) +
  geom_col(position = "dodge")

df_f1_rev %>% filter(group != "Top 1%") %>%
  ggplot() +
  geom_col(aes(x = ...1, y = value, fill = group), position = "dodge") +
  geom_text(aes(x = ...1, y = value, group = group, 
            label = scales::label_percent(accuracy=1)(value)), 
            position = position_dodge(width = 0.9)) + 
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 1. Global income and wealth inequality, 2021",
       x = "", y = "Share of total income or wealth", fill = "")

Interpretation: The global bottom 50% captures 8.5% of total income measured at Purchasing Power Parity (PPP). The global bottom 50% owns 2% of wealth (at Purchasing Power Parity). The global top 10% owns 76% of total Household wealth and captures 52% of total income in 2021. Note that top wealth holders are not necessarily top income holders. Incomes are measured after the operation of pension and unemployment systems and before taxes and transfers.
Sources and series: wir2022.wid.world/methodology.


4.1.9 F2: The poorest half lags behind: Bottom 50%, middle 40% and top 10% income shares across the world in 2021

df_f2 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F2")
df_f2

df_f2 %>% pivot_longer(cols = 3:5, names_to = "group", values_to = "value")

df_f2 %>% pivot_longer(cols = 3:5, names_to = "group", values_to = "value") %>%
  ggplot(aes(x = iso, y = value, fill = group)) +
  geom_col(position = "dodge")

4.1.10 Pivot data from long to wide:

pivot_wider() In Console: vignette(“pivot”)

pivot_wider(data, 
  names_from = <name of the column (or columns) to get the name of the output column>,
  values_from = <name of the column to get the value of the output>) 

pivot_wider(data, names_from = group, values_from = value) 

4.1.11 Practice: F4 and F13

F4 and F13 are similar. Please use pivot_longer to tidy the data and create charts.

4.1.11.1 Done Last Week

  • F12: Female share in global labor incomes, 1990-2020
  • F14: Global carbon inequality, 2019. Group contribution to world emissions (%)

4.1.12 F3: Top 10/Bottom 50 income gaps across the world, 2021

df_f3 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F3")
df_f3

4.1.13 F3: Top 10/Bottom 50 income gaps across the world, 2021 - Original


  • To 10 / Bottom 50 ratio has 5 classes: 5-12, 12-13, 13-16, 16-19, 19-140
df_f3$T10B50 %>% summary()

df_f3 %>% ggplot() + geom_histogram(aes(T10B50))

df_f3 %>% arrange(desc(T10B50))

df_f3 %>% 
  mutate(`Top 10 Bottom 50 Ratio` = cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), 
                                        include.lowest = FALSE)) 

world_map <- map_data("world")
df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), 
                                        include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + 
  geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), map = world_map) + 
  expand_limits(x = world_map$long, y = world_map$lat)

world_map_wir <- world_map
world_map_wir$region[
  world_map_wir$region=="Democratic Republic of the Congo"]<-"DR Congo"
world_map_wir$region[world_map_wir$region=="Republic of Congo"]<-"Congo"
world_map_wir$region[world_map_wir$region=="Ivory Coast"]<-"Cote dIvoire"
world_map_wir$region[world_map_wir$region=="Vietnam"]<-"Viet Nam"
world_map_wir$region[world_map_wir$region=="Russia"]<-"Russian Federation"
world_map_wir$region[world_map_wir$region=="South Korea"]<-"Korea"
world_map_wir$region[world_map_wir$region=="UK"]<-"United Kingdom"
world_map_wir$region[world_map_wir$region=="Brunei"]<-"Brunei Darussalam"
world_map_wir$region[world_map_wir$region=="Laos"]<-"Lao PDR"
world_map_wir$region[world_map_wir$region=="Cote dIvoire"]<-"Cote d'Ivoire"
world_map_wir$region[world_map_wir$region=="Cape Verde"]<- "Cabo Verde"
world_map_wir$region[world_map_wir$region=="Syria"]<- "Syrian Arab Republic"
world_map_wir$region[world_map_wir$region=="Trinidad"]<- "Trinidad and Tobago"
world_map_wir$region[world_map_wir$region=="Tobago"]<- "Trinidad and Tobago"

df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = 
    cut(T10B50, breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + 
  geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), 
    map = world_map_wir) + 
    expand_limits(x = world_map_wir$long, y = world_map_wir$lat)

df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = 
    cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), 
    map = world_map_wir) + expand_limits(x = world_map_wir$long, y = world_map_wir$lat) + 
  coord_map("orthographic", orientation = c(25, 60, 0))

df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = 
  cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), 
    map = world_map_wir) + expand_limits(x = world_map_wir$long, y = world_map_wir$lat) + 
  coord_map("orthographic", orientation = c(15, -80, 0))

df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = 
  cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), 
    map = world_map_wir) + 
  expand_limits(x = world_map_wir$long, y = world_map_wir$lat)

df_f3 %>% 
  mutate(`Top 10 Bottom 50 Ratio` = 
        cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + 
  geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), map = world_map_wir) + 
  expand_limits(x = world_map_wir$long, y = world_map_wir$lat)  + 
  labs(title = "Figure 3. Top 10/Bottom 50 income gaps across the world, 2021",
       x = "", y = "", fill = "Top 10/Bottom 50 ratio") +
  theme(legend.position="bottom", 
        axis.text.x=element_blank(), axis.ticks.x=element_blank(),
        axis.text.y=element_blank(), axis.ticks.y=element_blank()) + 
  scale_fill_brewer(palette='YlOrRd')


df_f3 %>% anti_join(world_map_wir, by = c("Country" = "region"))

Filtering joins

  • anti_join(x,y, ...): return all rows from x without a match in y.
  • semi_join(x,y, ...): return all rows from x with a match in y.

Check dplyr cheat sheet, and Posit Primers Tidy Data.


4.1.14 Remaining Charts

  • F5: Global income inequality: T10/B50 ratio, 1820-2020 - fit curve

  • F9: Average annual wealth growth rate, 1995-2021 - fit curve + alpha

  • F7: Global income inequality, 1820-2020 - pivot + fit curve

  • F10: The share of wealth owned by the global 0.1% and billionaires, 2021 - pivot + fit curve

  • F6: Global income inequality: Between vs. Within country inequality (Theil index), 1820-2020 - pivot + area

  • F11: Top 1% vs bottom 50% wealth shares in Western Europe and the US, 1910-2020 - pivot name_sep + fit curve

  • F8: The rise of private versus the decline of public wealth in rich countries, 1970-2020 - rename + pivot + pivot + fit curve

  • F15: Per capita emissions acriss the world, 2019 - add row names + dodge


4.1.15 F5: Global income inequality: T10/B50 ratio, 1820-2020

(df_f5 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F5"))

df_f5 %>% ggplot(aes(x = y, y = t10b50)) + geom_line() + geom_smooth(span=0.25, se=FALSE)

4.1.16 F9: Average annual wealth growth rate, 1995-2021 - fit curve + alpha

df_f9 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F9"); df_f9

df_f9 %>% 
  ggplot(aes(x = p, y = `Wealth growth 1995-2021`)) + geom_smooth(span = 0.30, se = FALSE)

4.1.17 F7: Global income inequality, 1820-2020 - pivot + fit curve

df_f7 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F7"); df_f7

df_f7 %>% 
  pivot_longer(cols = 2:4, names_to = "type", values_to = "value") %>%
  ggplot(aes(x = y, y = value, color = type)) +
  stat_smooth(formula = y~x, method = "loess", span = 0.25, se = FALSE)

4.1.18 F10: The share of wealth owned by the global 0.1% and billionaires, 2021 - pivot + fit curve

df_f10 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F10"); df_f10

df_f10 %>% 
  select(year, "Global Billionaire Wealth" = bn_hhweal, "Top 0.01%" = top0.1_hhweal) %>%
  pivot_longer(!year, names_to = "group",".value", values_to = "value")

df_f10 %>% 
  select(year, "Global Billionaire Wealth" = bn_hhweal, "Top 0.01%" = top0.1_hhweal) %>%
  pivot_longer(!year, names_to = "group",".value", values_to = "value") %>%
  ggplot() +
  stat_smooth(aes(x = year, y = value, color = group), formula = y~x, method = "loess", span = 0.25, se = FALSE)

4.1.19 F6: Global income inequality: Between vs. Within country inequality (Theil index), 1820-2020 - pivot + area

df_f6 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F6"); df_f6

df_f6 %>% select(year = "...1", 2:3) %>%
  pivot_longer(cols = 2:3, names_to = "type", values_to = "value") %>%
  mutate(types = factor(type, 
      levels = c("Within-country inequality", "Between-country inequality"))) %>%
  ggplot(aes(x = year, y = value, fill = types)) +
  geom_area() +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  scale_x_continuous(breaks = round(seq(1820, 2020, by = 20),1)) + 
  scale_fill_manual(values=rev(scales::hue_pal()(2)), 
      labels = function(x) str_wrap(x, width = 15)) +
  labs(title = "Figure 6. Global income inequality: 
       \nBetween vs. within country inequality (Theil index), 1820-2020",
       x = "", y = "Share of global inequality (% of total Theil index)", fill = "") + 
  annotate("text", x = 1850, y = 0.28, 
      label = stringr::str_wrap("1820: Between country inequality represents 11% 
                                of global inequality", width = 20), size = 3) + 
  annotate("text", x = 1980, y = 0.70, 
      label = stringr::str_wrap("1980: Between country inequality represents 57% 
                                of global inequality", width = 20), size = 3) +
  annotate("text", x = 1990, y = 0.30, 
      label = stringr::str_wrap("2020: Between country inequality represents 32% 
                                of global inequality", width = 20), size = 3)


4.1.20 F11: Top 1% vs bottom 50% wealth shares in Western Europe and the US, 1910-2020 - pivot name_sep + fit curve

df_f11 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F11"); df_f11

df_f11 %>% 
  rename(!year, US_bot50 = USbot50, US_top1 = UStop1, 
         EU_bot50 = EUbot50, EU_top1 = EUtop1) %>%
  pivot_longer(!year, names_to = c("group",".value"), names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value") %>%
  ggplot() +
  stat_smooth(aes(x = year, y = value, color = group, linetype = type), 
              span = 0.25, se = FALSE) +
  scale_x_continuous(breaks = round(seq(1910, 2020, by = 10),1)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 11. Top 1% vs bottom 50% wealth shares 
       \n in Western Europe and the US, 1910-2020", 
       x = "", y = "Share of total personal wealth (%)", color = "", linetype = "") +
  scale_linetype_manual(values = c("dotted","solid")) +
  annotate("text", x = 2000, y = 0.50, 
      label = stringr::str_wrap("Wealth inequality has been rising at 
        different speeds after a historical decline. The bottom 50% has always been 
                                extremely low.", width = 30), size = 3)

4.1.20.1 Step 1.

df_f11 %>% rename(!year, US_bot50 = USbot50, US_top1 = UStop1, 
                  EU_bot50 = EUbot50, EU_top1 = EUtop1) 

4.1.20.2 Step 2.

df_f11 %>% 
  rename(!year, US_bot50 = USbot50, US_top1 = UStop1, 
         EU_bot50 = EUbot50, EU_top1 = EUtop1) %>%
  pivot_longer(!year, names_to = c("group",".value"), names_sep = "_")

4.1.20.3 Step 2.


4.1.20.4 Step 3.

df_f11 %>% 
  rename(!year, US_bot50 = USbot50, US_top1 = UStop1, 
         EU_bot50 = EUbot50, EU_top1 = EUtop1) %>%
  pivot_longer(!year, names_to = c("group",".value"), 
               names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value") 

4.1.20.5 Step 3.



4.1.21 F8: The rise of private versus the decline of public wealth in rich countries, 1970-2020 - rename + pivot + pivot + fit curve

df_f8 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F8"); df_f8

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') %>%
  pivot_longer(!year, names_to = c("country",".value"), names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value") %>%
  ggplot() +
  stat_smooth(aes(x = year, y = value, color = country, linetype = type), 
              span = 0.25, se = FALSE, size=0.75) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 8. The rise of private versus the decline of public 
       wealth in rich countries, 1970-2020", 
       x = "", y = "wealth as as % of national income", color = "", type = "")

4.1.21.1 Step 1

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') 


4.1.21.2 Step 2.

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') %>%
  pivot_longer(!year, names_to = c("country",".value"), names_sep = "_") 


4.1.21.3 Step 3.

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') %>%
  pivot_longer(!year, names_to = c("country",".value"), names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value")


4.1.21.4 Step 3. Final Step

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') %>%
  pivot_longer(!year, names_to = c("country",".value"), names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value") %>%
  ggplot() +
  stat_smooth(aes(x = year, y = value, color = country, linetype = type), 
              formula = y~x, method = "loess", span = 0.25, se = FALSE, size=0.75) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 8. The rise of private versus the decline of public wealth 
       \nin rich countries, 1970-2020", 
       x = "", y = "wealth as as % of national income", color = "", type = "")


4.1.22 F15: Per capita emissions acriss the world, 2019 - add row names + dodge

df_f15 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F15"); df_f15

df_f15 %>% mutate(region = rep(regionWID[!is.na(regionWID)], each = 3)) %>%
  select(region, group, tcap) %>%
  ggplot(aes(x = region, y = tcap, fill = group)) +
  geom_col(position = "dodge") + 
  scale_x_discrete(labels = function(x) stringr::str_wrap(x, width = 10)) +
  labs(title = "Figure 15 Per capita emissions across the world, 2019", 
       x = "", y = "tonnes of CO2e per person per year", fill = "")

4.2 EDA Workflow

4.2.1 EDA Step 0

  1. Choose and clarify a topic to study.
  2. List questions to study
  3. Find data:
  • link to data with a url: universal resource locator in a webpage
  • download data in csv, Excel, etc.

Repeat the process during your EDA.

image

4.2.2 EDA by R Studio: Step 1

In RStudio,

1.1. Project

  • Create a new project: File > New Project; or
  • Open a project: File > Open Project, Open Project in New Session, Open Recent Project
  • Check there is a file project_name.Rproj in your project folder (directory)

1.2. data folder (directory) data

  • Create a data folder: Press New Folder at the right bottom pane; or
  • Confirm the data folder previously created: Press Files at the right bottom pane
  • If you follow 1, the data folder exists in your project folder

1.3. Move (or copy) data for the project to the data folder

  • If you downloaded the data, it is in your Download folder. Move it to data.
  • Check in your RStudio that your data is in data: Press Files at the right bottom pane and click data, the data folder.

4.2.3 EDA by R Studio: Step 2

2.1. Project Notebook: Memo

  • Create an R Notebook: File > New File > R Notebook

    • You can use R Notebook template in Moodle by moving the template (template.Rmd or template.nb.Rmd) file in your project folder or copy and paste the text file into your new R Notebook.
    • If you use template.nb.Rmd (R Notebook File), choose Open in Editor.
  • Add descriptive title.

2.2. Setup Code Chunk

  • Create a code chunk and add packages to use in the project and RUN the code.

    • library(tidyverse)
    • library(WDI)
    • or any other packages

2.3. Choose Source or Visual editor mode, and start editing Project Notebook

2.4. Edit a new file by saving as for a report

  • File > Save As…

4.2.4 EDA by R Studio: Step 3 - Importing Data

Assign a name you can recall easily when you import data. You may need to reload the data with options.

3.1. Use a package:

  • WDI, wir, eurostat, etc/
  • `wdi_shortname <- WDI(indicator = “indicator’s name”, … )
  • Store the data and use it: write_csv(wdi_shortname, "data/wdi_shortname.csv")
  • wdi_shortname <- read_csv("data/wdi_shortname.csv")

3.2. Use readr to read from data, your data folder

  • df1_shortname <- read_csv("data/file_name.csv")

3.3. Use readr to read using the url of the data

  • df2_shortname <- read_csv("url_of_the_data")
  • Store the data and use it: write_csv(df2_shortname, "data/df2_shortname.csv")
  • df2_shortname <- read_csv("data/df2_shortname.csv")

3.5. Use readxl to read Excel data. Add library(readxl) in the setup and run.

  • df4 <- read_excel("data/file_name.xlsx", sheet = 1)

References: Cheat Sheet - readr, readr, readxl


4.2.5 EDA by R Studio: Step 4 - Data Trasnformation

4.1. Look at the data: suppose df is the data frame

  • It is a good option to change into a tibble: dt <- as_tibble(df)
  • head(df), str(df), summary(df), dt, glimpse(dt)

4.2. Look at each variable

  • categorical? numerical?
  • factor? - forcats

4.3. Variation of each data: suppose x1 is a column name.

  • df %>% ggplot() + geom_histogram(aes(x1), bins = 30)

  • df %>% drop_na(x1): see the rows with a value in x1. If the value is NA, the row is not shown.

    • df_wo_na <- df %>% drop_na(x1) if you want to use only the rows without NA in x1

4.4. Use dpylr and tidyr to change column names, tidy data, and/or summarize data

  • rename, select, filter, arrange, mutate, pivot_longer(), pivot_wider(), group_by and summarize

References: Cheat Sheet - dplyr and tidyr, dplyr, tidyr


4.2.6 EDA by R Studio: Step 5 - Visualize Data

5.1. In combination with Stap 4 - data transformation, try various data visualization.

  • What type of variation occurs within my variables?
  • What type of covariation occurs between my variables?

5.2. Keep a record of what you can observe by the visualization

5.3. Edit the list of questions by adding or polishing

5.4. Select several informative chart and add options

5.5. Look at examples from the textbooks or teaching site to have better visualization

References: Cheat Sheet - ggplot2 ggplot2, ggplot2 book


4.2.7 EDA by R Studio: Step 6 - Conclusions and Questions for Further Study

  1. EDA is an iterative cycle that helps you understand what your data says. When you do EDA, you:

  2. Generate questions about your data

  3. Search for answers by visualising, transforming, and/or modeling your data

Use what you learn to refine your questions and/or generate new questions

EDA is an important part of any data analysis. You can use EDA to make discoveries about the world; or you can use EDA to ensure the quality of your data, asking questions about whether the data meets your standards or not.


4.2.8 Example: WDI


4.2.9 Example: WIR2022

4.3 The Week Five Assignment (in Moodle)

tidyr and WIR2022

  • Create an R Notebook of a Data Analysis containing the following and submit the rendered HTML file (eg. a3_123456.nb.html by replacing 123456 with your ID)
    1. create an R Notebook using the R Notebook Template in Moodle, save as a3_123456.Rmd,
    2. write your name and ID and the contents,
    3. run each code block,
    4. preview to create a3_123456.nb.html,
    5. submit a3_123456.nb.html to Moodle.
  1. Choose a data with at least two categorical variables and at least two numerical variables.

    • Information of the data: Name, Indicator, Description, Source, etc.
    • Explain why you chose the indicator
    • List questions you want to study

  1. Explore the data using visualization using ggplot2

    • Create various charts
    • Create at least one chart with at least two categorical variables and at least one numerical variable.
    • Create at least one chart with at least two numerical variables and at least one categorical variable.
  2. Observations based on your data visualization, and difficulties and questions encountered if any.

Due: 2023-01-23 23:59:00. Submit your R Notebook file in Moodle (The Fourth Assignment). Due on Monday!

5 Exploratory Data Analysis (EDA) V

5.1 Modeling

“Tidy data sets are all alike; but every messy data set is messy in its own way.” — Hadley Wickham

“all happy families are all alike; each unhappy family is unhappy in its own way” - Tolstoy’s Anna Karenina

Correlation

iris %>% select(-5) %>% cor()
             Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length    1.0000000  -0.1175698    0.8717538   0.8179411
Sepal.Width    -0.1175698   1.0000000   -0.4284401  -0.3661259
Petal.Length    0.8717538  -0.4284401    1.0000000   0.9628654
Petal.Width     0.8179411  -0.3661259    0.9628654   1.0000000

Galton’s data. Regression.

Normalization, standalization

SDGs Academy

Trend

df4 <- WDI(
  country="all",
  indicator = c("SP.POP.TOTL","MS.MIL.XPND.GD.ZS","MS.MIL.TOTL.P1","NY.GDP.MKTP.CD"),
  start = 1960,
  end = NULL,
  extra = FALSE,
  cache = NULL,
  latest = NULL,
  language = "en"
)
colnames(df4) <- c("Country","iso2c","iso3c","Year","Population","Mil_Exp","Total_Mil_HC","GDP")
df4

5.1.1 Tali

df_wdi_poverty <- WDI(
  country = "all", 
  indicator = c(national_poverty_rate = "SI.POV.NAHC", multidimentional_poverty_rate = "SI.POV.MDIM", gdpPercap = "NY.GDP.PCAP.KD", gini_indx = "SI.POV.GINI"), start = 1990,
    end = 2021,
  extra = TRUE
)
df_wdi_poverty %>%  
  group_by(country, year) %>%
  mutate(mean_gdp_country = mean(gdpPercap)) %>%
  mutate(mean_poverty_country= mean(national_poverty_rate)) %>%
  ungroup() %>%
    filter(!is.na(income)) %>%   filter(!(income=="Aggregates")) %>% ggplot(aes(x = log10(mean_gdp_country))) + geom_point(aes(y = mean_poverty_country, color = income)) +  labs(x = "GDP per capita", y = "poverty rate (% of population)", title = "Poverty rates and GDP per capita", subtitle="world countries, 1990-2021 average, by income level")
df_wdi_poverty %>%  
  group_by(country, year) %>%
  mutate(mean_gdp_country = mean(gdpPercap)) %>%
  mutate(mean_multipoverty_country= mean(multidimentional_poverty_rate)) %>%
  ungroup() %>%
    filter(!(region=="Aggregates")) %>% filter(!is.na(region)) %>% ggplot(aes(x = log10(mean_gdp_country))) + geom_point(aes(y = mean_multipoverty_country, color = region)) +  labs(x = "GDP per capita", y = "Multidimentinal poverty rate (% of population)", title = "Multidimentional Poverty rates and GDP per capita", subtitle="world countries, 1990-2021 average, by region")

index sdg, ghi, academy

moocs

R4DS: Model basics https://r4ds.had.co.nz/model-basics.html modelr: https://modelr.tidyverse.org

Tidymodels: https://www.tidymodels.org

Tidyverse Skills for Data Science https://jhudatascience.org/tidyversecourse/ https://jhudatascience.org/tidyversecourse/model.html

machine learning:A Gentle Introduction to tidymodels https://rviews.rstudio.com/2019/06/19/a-gentle-intro-to-tidymodels/

Tidy Modeling with R https://www.tmwr.org

5.1.2 Other Examples

5.2 Roudups

5.2.1 R Markdown Revisited

5.2.1.1 Literate Programming and Reproducible Research

Importing Data:

  1. Read a csv file: read_csv("data/file_name.csv")
  2. Download and import using a url of a csv file: read_csv(url)
  3. Read an Excel file: readxl::read_excel("data/excel_file_name.xlsx")
  4. Read from the clipboard: read_delim(clipboard())
  • Not reproducible unless clearly explained.

5.2.1.2 Code Chunk Options

https://yihui.org/knitr/options/

  • Chunk Name
  • Output: use document default
    • Show code and output: echo=TRUE, eval=TRUE - Default
    • Show output only: echo=FALSE
    • Show nothing (run code): include=FALSE
    • Show nothing (don’t run code): include=FALSE, eval=FALSE
  • Show message: message=TRUE, FALSE
  • Show warning: warning=TRUE, FALSE
  • Use Paged Tables: paged.print=TRUE, FALSE
  • Use custom figure size: width and height in inch.

5.2.1.3 Presentation and Paper

  1. Data Source

  2. Variables

  3. Problems

  4. Visualization

  5. Model

  6. Conclusions and Further Research

    WDI, WIR, etc

5.2.1.4 Word

Custom Word templates: https://bookdown.org/yihui/rmarkdown-cookbook/word-template.html

You can apply the styles defined in a Word template document to new Word documents generated from R Markdown. Such a template document is also called a “style reference document.” The key is that you have to create this template document from Pandoc first, and change the style definitions in it later. Then pass the path of this template to the reference_docx option of word_document

---
 word_document:
    reference_docx: "template.docx"
---

5.2.1.5 PowerPoint

PowerPoint presentation: https://bookdown.org/yihui/rmarkdown/powerpoint-presentation.html

Custom templates: https://bookdown.org/yihui/rmarkdown/powerpoint-presentation.html#ppt-templates

---
  powerpoint_presentation:
    reference_doc: my-styles.pptx
---

https://support.microsoft.com/en-us/office/create-and-save-a-powerpoint-template-ee4429ad-2a74-4100-82f7-50f8169c8aca

YouTube: How To Create A PowerPoint Template

LS0tCnRpdGxlOiAnUUFMTDQwMTogRGF0YSBBbmFseXNpcyBmb3IgUmVzZWFyY2hlcnMnCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIGJlYW1lcl9wcmVzZW50YXRpb246IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIGlvc2xpZGVzX3ByZXNlbnRhdGlvbjogCiAgICBkZl9wcmludDogcGFnZWQKICAgIHdpZGVzY3JlZW46IHllcwogICAgc21hbGxlcjogeWVzCi0tLQoKIyMgQ291cnNlIENvbnRlbnRzIHstfQoKMS4gMjAyMi4xMi4wNzogSW50cm9kdWN0aW9uOiBBYm91dCB0aGUgY291cnNlIFtsZWFkIGJ5IFRLXQogICAgLSBBbiBpbnRyb2R1Y3Rpb24gdG8gb3BlbiBhbmQgcHVibGljIGRhdGEsIGFuZCBkYXRhIHNjaWVuY2UKMi4gMjAyMi0xMi0xNDogRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAoRURBKSAxIFtsZWFkIGJ5IGhzXSAgCiAgICAtIFIgQmFzaWNzIHdpdGggUlN0dWRpbyBhbmQvb3IgUlN0dWRpby5jbG91ZDsgVG95IERhdGEKMy4gMjAyMi0xMi0yMTogRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAoRURBKSAyIFtsZWFkIGJ5IGhzXSAgIAogICAgLSBSIE1hcmtkb3duLCBgdGlkeXZlcnNlYCBJOiBgZHBseXJgOyBgZ2FwbWluZGVyYAo0LiAyMDIzLTAxLTExOiBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpIDMgW2xlYWQgYnkgaHNdICAKICAgIC0gYHRpZHl2ZXJzZWBJSTogYHJlYWRyYCwgYGdncGxvdDJgOyBQdWJsaWMgRGF0YSwgV0RJLCBXSVIsIGV0Ywo1LiAyMDIzLTAxLTE4OiBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpIDQgW2xlYWQgYnkgaHNdICAKICAgIC0gYHRpZHl2ZXJzZWAgSUlJOiBgdGlkeXJgLCBldGMuOyBXREksIFdJUiwgZXRjCjYuIDIwMjMtMDEtMjU6IEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkgNSBbbGVhZCBieSBoc10gIAogICAgLSBgdGlkeXZlcnNlYCBJVjsgV0RJLCBXSVIsIGV0Ywo3LiAyMDIzLTAyLTAxOiBJbnRyb2R1Y3Rpb24gdG8gUFBEQUMgICAgICAgICAKICAgIC0gUHJvYmxlbS1QbGFuLURhdGEtQW5hbHlzaXMtQ29uY2x1c2lvbiBDeWNsZTogW2xlYWQgYnkgVEtdCjguIDIwMjMtMDItMDg6IE1vZGVsIGJ1aWxkaW5nIEkgW2xlYWQgYnkgVEtdICAgIAogICAgLSBDb2xsZWN0aW5nIGFuZCB2aXN1YWxpemluZyBkYXRhIGFuZCBJbnRyb2R1Y3Rpb24gdG8gV0RJICAKICAgICAgICAgKFdvcmxkIERldmVsb3BtZW50IEluZGljYXRvcnMgYnkgV29ybGQgQmFuaykKOS4gMjAyMy0wMi0xNTogTW9kZWwgYnVpbGRpbmcgSUkgW2xlYWQgYnkgVEtdICAgIAogICAgLSBBbmFseXppbmcgZGF0YSBhbmQgY29tbXVuaWNhdGlvbnMKMTAuIDIwMjMtMDItMjI6IFByb2plY3QgUHJlc2VudGF0aW9uCgoKIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpIEkKCiMjIFIgd2l0aCBSIFN0dWRpbyBhbmQvb3IgUiBTdHVkaW8uY2xvdWQKCi0tLQoKIyMjIExlYXJuaW5nIFJlc291cmNlcwoKIyMjIyBUZXh0Ym9va3MgYW5kIFJlZmVyZW5jZXMKCiogIlIgZm9yIERhdGEgU2NpZW5jZSIgYnkgSGFkbGV5IFdpY2toYW0gYW5kIEdhcnJldHQgR3JvbGVtdW5kOiAKICAtIEZyZWUgT25saW5lIEJvb2s6IGh0dHBzOi8vcjRkcy5oYWQuY28ubnoKCiogVmlzaXQgYGJvb2tkb3duYCBzaXRlOiBodHRwczovL2Jvb2tkb3duLm9yZyAKICAtIE1hbnkgbW9yZSBvbiB0aGUgW2FyY2hpdmUgcGFnZV0oaHR0cHM6Ly9ib29rZG93bi5vcmcvaG9tZS9hcmNoaXZlLykuCgoKIyMjIEludGVyYWN0aXZlIEV4ZXJjaXNlcwoKKiBQb3NpdCBQcmltZXJzOmh0dHBzOi8vcG9zaXQuY2xvdWQvbGVhcm4vcHJpbWVyczogIAogIC0gVGhlIEJhc2ljcywgV29yayB3aXRoIERhdGEsIFZpc3VhbGl6ZSBEYXRhLCBUaWR5IFlvdXIgRGF0YSwgUmVwb3J0IFJlcHJvZHVjaWJseQoKKiB7c3dpcmx9IExlYXJuIFIsIGluIFI6IGh0dHBzOi8vc3dpcmxzdGF0cy5jb20KICAtIERlc2lnbmVkIGFuZCBkZXZlbG9wZWQgYnkgYSB0ZWFtIGF0IEpvaG5zIEhvcGtpbnMgVW5pdmVyc2l0eSBmb3IgYGNvdXJzZXJhYCBjb3Vyc2VzCgotLS0KCiMjIyBQb3NpdCBQcmltZXJzIGNyZWF0ZWQgYnkgYGxlYXJucmAKCiogW2BsZWFybnJgIEludGVyYWN0aXZlIFR1dG9yaWFscyBmb3IgUl0oaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9sZWFybnIvaW5kZXguaHRtbCkKCjo6OiB7LmJsb2NrfQojIyMjIFBvc2l0IFByaW1lcnMgaHR0cHM6Ly9wb3NpdC5jbG91ZC9sZWFybi9wcmltZXJzCgoxLiBUaGUgQmFzaWNzIC0tIFtyNGRzOiBFeHBsb3JlLCBJXShodHRwczovL3I0ZHMuaGFkLmNvLm56L2V4cGxvcmUtaW50cm8uaHRtbCNleHBsb3JlLWludHJvKQogIC0gW1Zpc3VhbGl6YXRpb24gQmFzaWNzXShodHRwczovL3JzdHVkaW8uY2xvdWQvbGVhcm4vcHJpbWVycy8xLjEpCiAgLSBbUHJvZ3JhbW1pbmcgQmFzaWNzXShodHRwczovL3JzdHVkaW8uY2xvdWQvbGVhcm4vcHJpbWVycy8xLjIpCjIuIFdvcmsgd2l0aCBEYXRhIC0tIFtyNGRzOiBXcmFuZ2xlLCBJXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3dyYW5nbGUtaW50cm8uaHRtbCN3cmFuZ2xlLWludHJvKQogIC0gV29ya2luZyB3aXRoIFRpYmJsZXMKICAtIElzb2xhdGluZyBEYXRhIHdpdGggZHBseXIKICAtIERlcml2aW5nIEluZm9ybWF0aW9uIHdpdGggZHBseXIKMy4gVmlzdWFsaXplIERhdGEgLS0gW3I0ZHM6IEV4cGxvcmUsIElJXShodHRwczovL3I0ZHMuaGFkLmNvLm56L2V4cGxvcmUtaW50cm8uaHRtbCNleHBsb3JlLWludHJvKQo0LiBUaWR5IFlvdXIgRGF0YSAtLSBbcjRkczogV3JhbmdsZSwgSUldKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovd3JhbmdsZS1pbnRyby5odG1sI3dyYW5nbGUtaW50cm8pCjUuIEl0ZXJhdGUgLS0gW3I0ZHM6IFByb2dyYW1dKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovcHJvZ3JhbS1pbnRyby5odG1sI3Byb2dyYW0taW50cm8pCjYuIFdyaXRlIEZ1bmN0aW9ucyAtLSBbcjRkczogUHJvZ3JhbV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9wcm9ncmFtLWludHJvLmh0bWwjcHJvZ3JhbS1pbnRybykKOjo6Ci0tLQoKIyMjIERhdGEgU2NpZW5jZSBhbmQgRURBCgojIyMjIFdpa2lwZWRpYSBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EYXRhX3NjaWVuY2UKCj4gQW4gaW50ZXItZGlzY2lwbGluYXJ5IGZpZWxkIHRoYXQgdXNlcyBzY2llbnRpZmljIG1ldGhvZHMsIHByb2Nlc3NlcywgYWxnb3JpdGhtcyBhbmQgc3lzdGVtcyB0byBleHRyYWN0IGtub3dsZWRnZSBhbmQgaW5zaWdodHMgZnJvbSBtYW55IHN0cnVjdHVyYWwgYW5kIHVuc3RydWN0dXJlZCBkYXRhLgoKKiBDcmVhdGUgSW5zaWdodHMKKiBJbXBhY3QgRGVjaXNpb24gTWFraW5nCiogTWFpbnRhaW4gJiBJbXByb3ZlIE92ZXJ0aW1lCgotLS0KCiMjIyBXaGF0IGlzIFI/CgojIyMjIFIgKHByb2dyYW1taW5nIGxhbmd1YWdlKSwgW1dpa2lwZWRpYV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUl8ocHJvZ3JhbW1pbmdfbGFuZ3VhZ2UpKQoKKiAqKlIgaXMgYSBwcm9ncmFtbWluZyBsYW5ndWFnZSoqIGFuZCAqKmZyZWUgc29mdHdhcmUqKiBlbnZpcm9ubWVudCBmb3IgKipzdGF0aXN0aWNhbCBjb21wdXRpbmcgYW5kIGdyYXBoaWNzKiogc3VwcG9ydGVkIGJ5IHRoZSBSIEZvdW5kYXRpb24gZm9yIFN0YXRpc3RpY2FsIENvbXB1dGluZy4gCgoqIFRoZSBSIGxhbmd1YWdlIGlzIHdpZGVseSB1c2VkIGFtb25nIHN0YXRpc3RpY2lhbnMgYW5kIGRhdGEgbWluZXJzIGZvciBkZXZlbG9waW5nIHN0YXRpc3RpY2FsIHNvZnR3YXJlIGFuZCBkYXRhIGFuYWx5c2lzLgoKKiBBICoqR05VIHBhY2thZ2UqKiwgdGhlIG9mZmljaWFsIFIgc29mdHdhcmUgZW52aXJvbm1lbnQgaXMgd3JpdHRlbiBwcmltYXJpbHkgaW4gQywgRm9ydHJhbiwgYW5kIFIgaXRzZWxmICh0aHVzLCBpdCBpcyBwYXJ0aWFsbHkgc2VsZi1ob3N0aW5nKSBhbmQgaXMgZnJlZWx5IGF2YWlsYWJsZSB1bmRlciB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UuIAoKLS0tCgojIyMjIEhpc3Rvcnkgb2YgUiBhbmQgbW9yZQoKIlIgUHJvZ3JhbW1pbmcgZm9yIERhdGEgU2NpZW5jZSIgYnkgUm9nZXIgUGVuZwoKKiBbQ2hhcHRlciAyLiBIaXN0b3J5IGFuZCBPdmVydmlldyBvZiBSXShodHRwczovL2Jvb2tkb3duLm9yZy9yZHBlbmcvcnByb2dkYXRhc2NpZW5jZS9oaXN0b3J5LWFuZC1vdmVydmlldy1vZi1yLmh0bWwpCiogW092ZXJ2aWV3IGFuZCBIaXN0b3J5IG9mIFI6IFlvdXR1YmUgdmlkZW9dKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9U1RpaFRuVlNabkkmZmVhdHVyZT15b3V0dS5iZSkKCi0tLQoKIyMjIFdoeSBSPyAtLSBSZXNwb25zZXMgYnkgSGFkbGV5IFdpY2toYW0KCiMjIyMgW3I0ZHNdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovaW50cm9kdWN0aW9uLmh0bWwjcHl0aG9uLWp1bGlhLWFuZC1mcmllbmRzKTogUiBpcyBhIGdyZWF0IHBsYWNlIHRvIHN0YXJ0IHlvdXIgZGF0YSBzY2llbmNlIGpvdXJuZXkgYmVjYXVzZQoKKiBSIGlzIGFuIGVudmlyb25tZW50IGRlc2lnbmVkIGZyb20gdGhlIGdyb3VuZCB1cCB0byBzdXBwb3J0IGRhdGEgc2NpZW5jZS4gCiogUiBpcyBub3QganVzdCBhIHByb2dyYW1taW5nIGxhbmd1YWdlLCBidXQgaXQgaXMgYWxzbyBhbiBpbnRlcmFjdGl2ZSBlbnZpcm9ubWVudCBmb3IgZG9pbmcgZGF0YSBzY2llbmNlLiAKKiBUbyBzdXBwb3J0IGludGVyYWN0aW9uLCBSIGlzIGEgbXVjaCBtb3JlIGZsZXhpYmxlIGxhbmd1YWdlIHRoYW4gbWFueSBvZiBpdHMgcGVlcnMuIAoKLS0tCgojIyMjIFdoeSBSIHRvZGF5PwoKV2hlbiB5b3UgdGFsayBhYm91dCBjaG9vc2luZyBwcm9ncmFtbWluZyBsYW5ndWFnZXMsIEkgYWx3YXlzIHNheSB5b3Ugc2hvdWxkbuKAmXQgcGljayB0aGVtIGJhc2VkIG9uIHRlY2huaWNhbCBtZXJpdHMsIGJ1dCByYXRoZXIgcGljayB0aGVtIGJhc2VkIG9uIHRoZSBjb21tdW5pdHkuIEFuZCBJIHRoaW5rIHRoZSBSIGNvbW11bml0eSBpcyBsaWtlIHJlYWxseSwgcmVhbGx5IHN0cm9uZywgdmlicmFudCwgZnJlZSwgd2VsY29taW5nLCBhbmQgZW1icmFjZXMgYSB3aWRlIHJhbmdlIG9mIGRvbWFpbnMuIFNvLCBpZiB0aGVyZSBhcmUgbGlrZSBwZW9wbGUgbGlrZSB5b3UgdXNpbmcgUiwgdGhlbiB5b3VyIGxpZmUgaXMgZ29pbmcgdG8gYmUgbXVjaCBlYXNpZXIuIFRoYXTigJlzIHRoZSBmaXJzdCByZWFzb24uIAoKKipJbnRlcnZpZXcqKjogWyJBZHZpY2UgdG8gWW91bmcgKGFuZCBPbGQpIFByb2dyYW1tZXJzLCBILiBXaWNraGFtIl0oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vMjAxOC8wOC9hZHZpY2UtdG8teW91bmctYW5kLW9sZC1wcm9ncmFtbWVycy1hLWNvbnZlcnNhdGlvbi13aXRoLWhhZGxleS13aWNraGFtLykKCi0tLQoKIyMjIFdoYXQgaXMgUlN0dWRpbz8gaHR0cHM6Ly9wb3NpdC5jb20KCj4gUlN0dWRpbyBpcyBhbiBpbnRlZ3JhdGVkIGRldmVsb3BtZW50IGVudmlyb25tZW50LCBvciBJREUsIGZvciBSIHByb2dyYW1taW5nLiAKCiMjIyMgUiBTdHVkaW8gKFdpa2lwZWRpYSkKClJTdHVkaW8gaXMgYW4gaW50ZWdyYXRlZCBkZXZlbG9wbWVudCBlbnZpcm9ubWVudCAoSURFKSBmb3IgUiwgYSBwcm9ncmFtbWluZyBsYW5ndWFnZSBmb3Igc3RhdGlzdGljYWwgY29tcHV0aW5nIGFuZCBncmFwaGljcy4gSXQgaXMgYXZhaWxhYmxlIGluIHR3byBmb3JtYXRzOiBSU3R1ZGlvIERlc2t0b3AgaXMgYSByZWd1bGFyIGRlc2t0b3AgYXBwbGljYXRpb24gd2hpbGUgUlN0dWRpbyBTZXJ2ZXIgcnVucyBvbiBhIHJlbW90ZSBzZXJ2ZXIgYW5kIGFsbG93cyBhY2Nlc3NpbmcgUlN0dWRpbyB1c2luZyBhIHdlYiBicm93c2VyLgoKLS0tCgojIyMgSW5zdGFsbGF0aW9uIG9mIFIgYW5kIFIgU3R1ZGlvCgojIyMjIFIgSW5zdGFsbGF0aW9uCgpUbyBkb3dubG9hZCBSLCBnbyB0byBDUkFOLCB0aGUgY29tcHJlaGVuc2l2ZSBSIGFyY2hpdmUgbmV0d29yay4gQ1JBTiBpcyBjb21wb3NlZCBvZiBhIHNldCBvZiBtaXJyb3Igc2VydmVycyBkaXN0cmlidXRlZCBhcm91bmQgdGhlIHdvcmxkIGFuZCBpcyB1c2VkIHRvIGRpc3RyaWJ1dGUgUiBhbmQgUiBwYWNrYWdlcy4gRG9u4oCZdCB0cnkgYW5kIHBpY2sgYSBtaXJyb3IgdGhhdOKAmXMgY2xvc2UgdG8geW91OiBpbnN0ZWFkIHVzZSB0aGUgY2xvdWQgbWlycm9yLCBodHRwczovL2Nsb3VkLnItcHJvamVjdC5vcmcsIHdoaWNoIGF1dG9tYXRpY2FsbHkgZmlndXJlcyBpdCBvdXQgZm9yIHlvdS4KCkEgbmV3IG1ham9yIHZlcnNpb24gb2YgUiBjb21lcyBvdXQgb25jZSBhIHllYXIsIGFuZCB0aGVyZSBhcmUgMi0zIG1pbm9yIHJlbGVhc2VzIGVhY2ggeWVhci4gSXTigJlzIGEgZ29vZCBpZGVhIHRvIHVwZGF0ZSByZWd1bGFybHkuCgojIyMjIFIgU3R1ZGlvIEluc3RhbGxhdGlvbgoKRG93bmxvYWQgYW5kIGluc3RhbGwgaXQgZnJvbSBodHRwOi8vd3d3LnJzdHVkaW8uY29tL2Rvd25sb2FkLiAKClJTdHVkaW8gaXMgdXBkYXRlZCBhIGNvdXBsZSBvZiB0aW1lcyBhIHllYXIuIFdoZW4gYSBuZXcgdmVyc2lvbiBpcyBhdmFpbGFibGUsIFJTdHVkaW8gd2lsbCBsZXQgeW91IGtub3cuCgotLS0KCiMjIyBSIFN0dWRpbwoKIyMjIyBUaGUgRmlyc3QgU3RlcAoxLiBTdGFydCBSIFN0dWRpbyBBcHBsaWNhdGlvbgoyLiBUb3AgTWVudTogRmlsZSA+IE5ldyBQcm9qZWN0ID4gTmV3IERpcmVjdG9yeSA+IE5ldyBQcm9qZWN0ID4gX0RpcmVjdG9yeSBuYW1lIG9yIEJyb3dzZSB0aGUgZGlyZWN0b3J5IGFuZCBjaG9vc2UgdGhlIHBhcmVudCBkaXJlY3RvcnkgeW91IHdhbnQgdG8gY3JlYXRlIHRoZSBkaXJlY3RvcnlfCgojIyMjIFdoZW4gWW91IFN0YXJ0IHRoZSBQcm9qZWN0CjEuIEdvIHRvIHRoZSBkaXJlY3RvcnkgeW91IGNyZWF0ZWQKMi4gRG91YmxlIGNsaWNrIF8nRGlyZWN0b3J5IE5hbWUnLlJwcm9qCiAgCk9yLAoKMS4gU3RhcnQgUiBTdHVkaW8KMi4gRmlsZSA+IE9wZW4gUHJvamVjdCAob3IgY2hvb3NlIGZyb20gUmVjZW50IFByb2plY3QpCgpfSW4gdGhpcyB3YXkgdGhlIHdvcmtpbmcgZGlyZWN0b3J5IG9mIHRoZSBzZXNzaW9uIGlzIHNldCB0byB0aGUgcHJvamVjdCBkaXJlY3RvcnkgYW5kIFIgY2FuIHNlYXJjaCByZWxldGVkIGZpbGVzIHdpdGhvdXQgZGlmZmljdWx0eV8gKGBnZXR3ZCgpYCwgYHNldHdkKClgKQoKLS0tCgojIyMgUG9zaXQgQ2xvdWQKClJTdHVkaW8gQ2xvdWQgaXMgYSBsaWdodHdlaWdodCwgY2xvdWQtYmFzZWQgc29sdXRpb24gdGhhdCBhbGxvd3MgYW55b25lIHRvIGRvLCBzaGFyZSwgdGVhY2ggYW5kIGxlYXJuIGRhdGEgc2NpZW5jZSBvbmxpbmUuCgojIyMjIENsb3VkIEZyZWUKCiogVXAgdG8gMTUgcHJvamVjdHMgdG90YWwKKiAxIHNoYXJlZCBzcGFjZSAoNSBtZW1iZXJzIGFuZCAxMCBwcm9qZWN0cyBtYXgpCiogMTUgcHJvamVjdCBob3VycyBwZXIgbW9udGgKKiBVcCB0byAxIEdCIFJBTSBwZXIgcHJvamVjdAoqIFVwIHRvIDEgQ1BVIHBlciBwcm9qZWN0CiogVXAgdG8gMSBob3VyIGJhY2tncm91bmQgZXhlY3V0aW9uIHRpbWUKCi0tLQoKIyMjIyBIb3cgdG8gU3RhcnQgUG9zaXQgQ2xvdWQKCjEuIEdvIHRvIGh0dHBzOi8vcG9zaXQuY2xvdWQvCjIuIFNpZ24gVXA6IF90b3AgcmlnaHRfCiAgLSBFbWFpbCBhZGRyZXNzIG9yIEdvb2dsZSBhY2NvdW50CjMuIE5ldyBQcm9qZWN0OiBfUHJvamVjdCBOYW1lXwo0LiBSIENvbnNvbGUKCgoKIyMgTGV0J3MgR2V0IFN0YXJ0ZWQKClN0YXJ0IFJTdHVkaW8gYW5kIGNyZWF0ZSBhIHByb2plY3QsIG9yIGxvZ2luIHRvIFBvc2l0IENsb3VkIGFuZCBjcmVhdGUgYSBwcm9qZWN0LgoKLS0tCgojIyMgVGhlIEZpcnN0IEV4YW1wbGVzCgpJbnB1dCB0aGUgZm9sbG93aW5nIGNvZGVzIGludG8gQ29uc29sZSBpbiB0aGUgbGVmdCBib3R0b20gcGFuZS4KCiogVGhlIGZpcnN0IHR3bzoKCmBgYHtyfQpoZWFkKGNhcnMpCmBgYAoKLS0tCgpgYGB7cn0Kc3RyKGNhcnMpCmBgYAoKLS0tCgoqIFR3byBtb3JlOgoKYGBge3J9CnN1bW1hcnkoY2FycykKYGBgCgotLS0KCmBgYHtyIGV2YWw9RkFMU0V9CnBsb3QoY2FycykKYGBgCgpgYGB7ciBjYXJzLXBsb3QsIGVjaG89RkFMU0V9CnBsb3QoY2FycykKYGBgCgotLS0KCiogQW5kIHRocmVlIG1vcmU6CgpgYGB7ciBldmFsPUZBTFNFfQpwbG90KGNhcnMpICMgY2FyczogU3BlZWQgYW5kIFN0b3BwaW5nIERpc3RhbmNlcyBvZiBDYXJzCmFibGluZShsbShjYXJzJGRpc3R+Y2FycyRzcGVlZCkpCmBgYApgYGB7ciBlY2hvPUZBTFNFfQpwbG90KGNhcnMpICMgY2FyczogU3BlZWQgYW5kIFN0b3BwaW5nIERpc3RhbmNlcyBvZiBDYXJzCmFibGluZShsbShjYXJzJGRpc3R+Y2FycyRzcGVlZCkpCmBgYAoKLS0tCgpgYGB7cn0KbG0oY2FycyRkaXN0fmNhcnMkc3BlZWQpCmBgYAoKLS0tCgpgYGB7cn0Kc3VtbWFyeShsbShjYXJzJGRpc3R+Y2FycyRzcGVlZCkpCmBgYAoKLS0tCgojIyMjIEJyaWVmIEV4cGxhbmF0aW9uCgoqIGBoZWFkKGNhcnMpYDogVGhlIGZpcnN0IDYgcm93cyBvZiB0aGUgcHJlLWluc3RhbGxlZCBkYXRhIGBjYXJzYC4KKiBgc3RyKGNhcnMpYDogVGhlIGRhdGEgc3RydWN0dXJlIG9mIHRoZSBwcmUtaW5zdGFsbGVkIGRhdGEgYGNhcnNgLgoqIGBzdW1tYXJ5KGNhcnMpYDogVGhlIHN1bW1hcnkgb2YgdGhlIHByZS1pbnN0YWxsZWQgZGF0YSBgY2Fyc2AuCiogYHBsb3QoY2FycylgOiBBIHNjYXR0ZXIgcGxvdCBvZiB0aGUgcHJlLWluc3RhbGxlZCBkYXRhIGBjYXJzYC4KICAtIGBwbG90KGNhcnMkZGlzdH5jYXJzJHNwZWVkKWAKICAtIGBjYXJzJGRpc3RgLCBgY2FycyRbWzJdXWAsIGBjYXJzWywyXWAgYXJlIHNhbWUKKiBgYWJsaW5lKGxtKGNhcnMkZGlzdH5jYXJzJHNwZWVkKSlgOiBBZGQgYSByZWdyZXNzaW9uIGxpbmUgb2YgYSBsaW5lYXIgbW9kZWwKKiBgbG0oY2FycyRkaXN0fmNhcnMkc3BlZWQpYDogVGhlIGVxdWF0aW9uIG9mIHRoZSByZWdyZXNzaW9uIGxpbmUKKiBgc3VtbWFyeShsbShjYXJzJGRpc3R+Y2FycyRzcGVlZClgOiBUaGUgc3VtbWFyeSBvZiB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwKCi0tLQoKYGBge3IsIGV2YWw9RkFMU0V9Cmhpc3QoY2FycyRkaXN0KQpgYGAKYGBge3IsIGVjaG89RkFMU0V9Cmhpc3QoY2FycyRkaXN0KQpgYGAKCi0tLQoKYGBge3IsIGV2YWw9RkFMU0V9Cmhpc3QoY2FycyRzcGVlZCkKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpoaXN0KGNhcnMkc3BlZWQpCmBgYAoKLS0tCgojIyMjIFZpZXcgYW5kIGhlbHAKCiogYFZpZXcoY2FycylgCiogYD9jYXJzYDogc2FtZSBhcyBgaGVscChjYXJzKWAKKiBgPz9jYXJzYDogc2FtZSBhcyBgaGVscC5zZWFyY2goImNhcnMiKQoKIyMjIyBgZGF0YXNldHNgCgoqIGA/ZGF0YXNldHNgCiogYGxpYnJhcnkoaGVscCA9ICJkYXRhc2V0cyIpYAoKKiBgZGF0YSgpYCBzaG93cyBhbGwgZGF0YSBhbHJlYWR5IGF0dGFjaGVkIGFuZCBhdmFpbGFibGUuCgotLS0KCiMjIyBQcmFjdGljdW0KClBpY2sgYSBkYXRhIGluIHRoZSBkYXRhc2V0cyBwYWNrYWdlIGFuZCB0cnkKCiogYGhlYWQoKWAKKiBgc3RyKClgCiogYHN1bW1hcnkoKWAKCmFuZCBzb21lIG1vcmUuCgotLS0KCiMjIyMgYGlyaXNgCgpgYGB7cn0KaGVhZChpcmlzKQpgYGAKCi0tLQoKYGBge3J9CnN0cihpcmlzKQpgYGAKCi0tLQoKYGBge3J9CnN1bW1hcnkoaXJpcykKYGBgCgotLS0KCkNhbiB5b3UgcGxvdD8KCmBgYHtyIGV2YWw9RkFMU0V9CnBsb3QoaXJpcyRTZXBhbC5MZW5ndGgsIGlyaXMkU2VwYWwuV2lkdGgpCmBgYApgYGB7ciBlY2hvPUZBTFNFfQpwbG90KGlyaXMkU2VwYWwuTGVuZ3RoLCBpcmlzJFNlcGFsLldpZHRoKQpgYGAKCiMjIGB0aWR5dmVyc2VgIFBhY2thZ2VzCgojIyMgQnJpZWYgSW50cm9kdWN0aW9uIHRvIFIgb24gUlN0dWRpbwoKIyMjIyBGb3VyIFBhbmVzIGFuZCBUYWJzCgoxLiBUb3AgTGVmdDogU291cmNlIEVkaXRvcgoyLiBUb3AgUmlnaHQ6IEVudmlyb25tZW50LCBIaXN0b3J5LCBldGMuCjMuIEJvdHRvbSBMZWZ0OiBDb25zb2xlLCBUZXJtaW5hbCwgUmVuZGVyLCBCYWNrZ3JvdW5kIEpvYnMKNC4gQm90dG9tIFJpZ2h0OiBGaWxlcywgUGxvdHMsIFBhY2thZ2VzLCBIZWxwLCBWaWV3ZXIsIFByZXNlbnRhdGlvbgoKLS0tCgojIyMjIFNldCB1cAoKKiBIaWdobHkgcmVjb21tZW5kIHRvIHNldCB0aGUgbGFuZ3VhZ2UgdG8gYmUgIkVuZ2xpc2giLgoqIENyZWF0ZSAiZGF0YSIgZGlyZWN0b3J5LgoKYGBge3Igd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0KU3lzLnNldGVudihMQU5HID0gImVuIikKZGlyLmNyZWF0ZSgiZGF0YSIpCmBgYAoKLS0tCgojIyMjIFRocmVlIFdheXMgdG8gUnVuIENvZGVzCgoxLiBDb25zb2xlIC0gQm90dG9tIExlZnQgUGFuZQoyLiBSIFNjcmlwdCAtIHB1bGwgZG93biBtZW51IHVuZGVyIEZpbGUKMy4gUiBOb3RlYm9vaywgUiBNYXJrZG93biAtIHB1bGwgZG93biBtZW51IHVuZGVyIEZpbGUKCi0tLQoKIyMjIFNlY29uZCBXYXk6IFIgU2NyaXB0CgojIyMjIEV4YW1wbGVzOiBSIFNjcmlwdHMgaW4gTW9vZGxlCgoqIGBiYXNpY3MuUmAKKiBgY29yb25hdmlydXMuUmAKCjEuIENvcHkgYSBzY3JpcHQgaW4gTW9vZGxlOiBfe2ZpbGUgbmFtZX0uUl8KMi4gSW4gUlN0dWRpbyAoY3JlYXRlIFByb2plY3QgaW4gUlN0dWRpbykgY2hvb3NlIEZpbGUgPiBOZXcgRmlsZSA+IFIgU2NyaXB0IGFuZCBwYXN0ZSBpdC4KMy4gQ2hvb3NlIEZpbGUgPiBTYXZlIHdpdGggYSBuYW1lOyBlLmcuIF97ZmlsZSBuYW1lc31fICguUiB3aWxsIGJlIGFkZGVkIGF1dG9tYXRpY2FsbHkpCgpUbyBydW4gYSBjb2RlOiBhdCB0aGUgY3Vyc29yIHByZXNzICpDdHJsK1NoaWZ0K0VudGVyKiAoV2luKSBvciAqQ21kK1NoaWZ0K0VudGVyKiAoTWFjKS4gCgotLS0KCiMjIyBQYWNrYWdlcwoKUiBwYWNrYWdlcyBhcmUgZXh0ZW5zaW9ucyB0byB0aGUgUiBzdGF0aXN0aWNhbCBwcm9ncmFtbWluZyBsYW5ndWFnZS4gUiBwYWNrYWdlcyBjb250YWluIGNvZGUsIGRhdGEsIGFuZCBkb2N1bWVudGF0aW9uIGluIGEgc3RhbmRhcmRpc2VkIGNvbGxlY3Rpb24gZm9ybWF0IHRoYXQgY2FuIGJlIGluc3RhbGxlZCBieSB1c2VycyBvZiBSLCB0eXBpY2FsbHkgdmlhIGEgY2VudHJhbGlzZWQgc29mdHdhcmUgcmVwb3NpdG9yeSBzdWNoIGFzIENSQU4gKHRoZSBDb21wcmVoZW5zaXZlIFIgQXJjaGl2ZSBOZXR3b3JrKS4KCiMjIyMgSW5zdGFsbGF0aW9uIGFuZCBhdHRhY2hlbWVudAoKWW91IGNhbiBpbnN0YWxsIHBhY2thZ2VzIGJ5ICJJbnN0YWxsIFBhY2thZ2VzLi4uIiB1bmRlciAiVG9vbCIgaW4gdGhlIHRvcCBtZW51LgoKKiBgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIilgCiogYGluc3RhbGwucGFja2FnZXMoInJtYXJrZG93biIpYAoKLS0tCgojIyMgVGhpcmQgV2F5OiBSIE5vdGVib29rCgpDaG9vc2UgUiBOb3RlYm9vayBmcm9tIHRoZSBwdWxsIGRvd24gRmlsZSBtZW51IGluIHRoZSB0b3AgYmFyLgoKIyMjIEVkaXQgWUFNTAoKKipEZWZhdWx0KiBpcyBhcyBmb2xsb3dzKioKCmBgYAotLS0KdGl0bGU6ICJSIE5vdGVib29rIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCmBgYAoKLS0tCgoqKlRlbXBsYXRlKioKCmBgYAotLS0KdGl0bGU6ICJUaXRsZSBvZiBSIE5vdGVib29rIgphdXRob3I6ICJJRCBhbmQgWW91ciBOYW1lIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiIApvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiMgICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKIyAgICB0b2M6IHRydWUKIyAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCmBgYAoKKiBEb24ndCBjaGFuZ2UgdGhlIGZvcm1hdC4gSW5kZW50aW9uIG1hdHRlcnMuCiogVGhlIHN0YXRlbWVudCBhZnRlciBcIyBpcyBpZ25vcmVkLgoqIERhdGUgaXMgYXV0b21hdGljYWxseSBpbnNlcnRlZCB3aGVuIHlvdSBjb21waWxlIHRoZSBmaWxlLgoqIFlvdSBjYW4gcmVwbGFjZSAiYHIgU3lzLkRhdGUoKWAiIGJ5ICIyMDIyLTEyLTE0IiBvciBpbiBhbnkgZGF0ZSBmb3JtYXQgc3Vycm91bmRlZCBieSBkb3VibGUgcXVvdGF0aW9uIG1hcmtzLgoqIFNlY3Rpb24gbnVtYmVyczogLSBkZWZhdWx0IGlzIGBudW1iZXJfc2VjdGlvbnM6IG5vYC4KKiBUYWJsZSBvZiBjb250ZW50cywgYHRvYzogdHJ1ZWAgLSBkZWZhdWx0IGlzIGB0b2M6IGZhbHNlYC4KKiBGbG9hdGluZyB0YWJsZSBvZiBjb250ZW50cyBpbiBIVE1MIG91dHB1dCwgYHRvY19mbG9hdDogdHJ1ZWAgLSBkZWZhdWx0IGlzIGB0b2NfZmxvYXQ6IGZhbHNlYAoKLS0tCgojIyMgQ3JlYXRlIGEgQ29kZSBDaHVuayB0byBBdHRhY2ggUGFja2FnZXMKCkluc2VydCBDaHVuayBpbiBDb2RlIHB1bGwgZG93biBtZW51IGluIHRoZSB0b3AgYmFyLCBvciB1c2UgdGhlIDxrYmQ+Qzwva2JkPiBidXR0b24gb24gdG9wLiBZb3UgY2FuIHVzZSBzaG9ydGN1dCBrZXlzIGxpc3RlZCB1bmRlciBUb29scyBpbiB0aGUgdG9wIGJhci4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKIyMgRmlyc3QgRXhhbXBsZQoKIyMjIEltcG9ydGluZyBkYXRhCgpMZXQgdXMgYXNzaWduIHRoZSBgaXJpc2AgZGF0YSBpbiB0aGUgcHJlLWluc3RhbGxlZCBwYWNrYWdlIGBkYXRhc2V0c2AgdG8gYGRmX2lyaXNgLiBZb3UgY2FuIGdpdmUgYW55IG5hbWUgc3RhcnRpbmcgZnJvbSBhbiBhbHBoYWJldCwgdGhvdWdoIHRoZXJlIGFyZSBzb21lIHJ1bGVzLiAKCmBgYHtyfQpkZl9pcmlzIDwtIGRhdGFzZXRzOjppcmlzCmNsYXNzKGRmX2lyaXMpCmBgYAoKVGhlIGNsYXNzIG9mIGRhdGEgYGlyaXNgIGlzIGBkYXRhLmZyYW1lYCwgdGhlIGJhc2ljIGRhdGEgY2xhc3Mgb2YgUi4gWW91IGNhbiBhc3NpZ24gdGhlIHNhbWUgZGF0YSBhcyBhIGB0aWJibGVgLCB0aGUgZGF0YSBjbGFzcyBvZiBgdGlkeXZlcnNlYCBhcyBmb2xsb3dzLgoKYGBge3J9CnRibF9pcmlzIDwtIGFzX3RpYmJsZShkYXRhc2V0czo6aXJpcykKY2xhc3ModGJsX2lyaXMpCmBgYAoKKiBgZGZfaXJpcyA8LSBpcmlzYCBjYW4gcmVwbGFjZSAgYGRmX2lyaXMgPC0gZGF0YXNldHM6OmlyaXNgIGJlY2F1c2UgdGhlIHBhY2thZ2UgYGRhdGFzZXRzYCBpcyBpbnN0YWxsZWQgYW5kIGF0dGFjaGVkIGFzIGRlZmF1bHQuIFNpbmNlIHlvdSBtYXkgaGF2ZSBvdGhlciBkYXRhIGNhbGxlZCBgaXJpc2AgaW5jbHVkZWQgaW4gYSBkaWZmZXJlbnQgcGFja2FnZSBvciB5b3UgbWF5IGhhdmUgY2hhbmdlZCBgaXJpc2AgYmVmb3JlLCBpdCBpcyBzYWZlciB0byBzcGVjaWZ5IHRoZSBuYW1lIG9mIHRoZSBwYWNrYWdlIHdpdGggdGhlIG5hbWUgb2YgdGhlIGRhdGEuCiogV2l0aGluIFIgTm90ZWJvb2sgb3IgaW4gQ29uc29sZSwgeW91IG1heSBnZXQgZGlmZmVyZW50IG91dHB1dCwgYW5kIGB0Zl9pcmlzYCBhbmQgYHRibF9pcmlzYCBiZWhhdmUgZGlmZmVyZW50bHkuIEl0IGlzIGJlY2F1c2Ugb2YgdGhlIGRlZmF1bHQgc2V0dGluZ3Mgb2YgUiBNYXJrZG93bi4gCgotLS0KCiMjIyBMb29rIGF0IHRoZSBkYXRhCgojIyMjIFNldmVyYWwgd2F5cyB0byB2aWV3IHRoZSBkYXRhLgoKVGhlIGBWaWV3YCBjb21tYW5kIG9wZW4gdXAgYSB3aW5kb3cgdG8gc2hvdyB0aGUgY29udGVudHMgb2YgdGhlIGRhdGEgYW5kIHlvdSBjYW4gdXNlIHRoZSBmaWx0ZXIgYXMgd2VsbC4KCmBgYHtyIHZpZXdpcmlzLCBldmFsID0gRkFMU0V9ClZpZXcoZGZfaXJpcykKYGBgCgotLS0KClRoZSBmb2xsb3dpbmcgc2ltcGxlIGNvbW1hbmQgYWxzbyBzaG93cyB0aGUgZGF0YS4gCmBgYHtyIGRmaXJpc30KZGZfaXJpcwpgYGAKClRoZSBvdXRwdXQgd2l0aGluIFIgTm90ZWJvb2sgaXMgYSB0aWJibGUgc3R5bGUuIFRyeSB0aGUgc2FtZSBjb21tYW5kIGluIENvbnNvbGUuCgotLS0KCmBgYHtyIHNsaWNlMTBpcmlzfQpzbGljZShkZl9pcmlzLCAxOjEwKQpgYGAKCgpgYGB7ciBvbmUydGVufQoxOjEwCmBgYApgCi0tLQoKIyMjIyBEYXRhIFN0cnVjdHVyZQoKTGV0IHVzIGxvb2sgYXQgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YS4gWW91IGNhbiB0cnkgYHN0cihkZl9pcmlzKWAgb24gQ29uc29sZSBvciBieSBhZGRpbmcgYSBjb2RlIGNodW5rIGluIFIgTm90ZWJvb2sgaW50cm9kdWNpbmcgbGF0ZXIuCgpgYGB7ciBnbGltcHNlOmVpcmlzfQpnbGltcHNlKGRmX2lyaXMpCmBgYAoKVGhlcmUgYXJlIHNpeCB0eXBlcyBvZiBkYXRhIGluIFI7IERvdWJsZSwgSW50ZWdlciwgQ2hhcmFjdGVyLCBMb2dpY2FsLCBSYXcsIENvbXBsZXguCgpUaGUgbmFtZXMgYWZ0ZXIgJCBhcmUgY29sdW1uIG5hbWVzLiBJZiB5b3UgY2FsbCBgZGZfaXJpcyRTcGVjaWVzYCwgeW91IGhhdmUgdGhlIFNwZWNpZXMgY29sdW1uLiBTcGVjaWVzIGlzIGluIHRoZSA1dGggY29sbHVtbiwgYHR5cGVvZihkZl9pcmlzW1s1XV0pYCBkb2VzIHRoZSBzYW1lIGFzIHRoZSBuZXh0LiAKCmBkZl9pcmlzWzIsNF0gPSBgYHIgZGZfaXJpc1syLDRdYCBpcyB0aGUgZm91cnRoIGVudHJ5IG9mIFNlcGFsLldpZHRoLgoKLS0tCgpgYGB7cn0KdHlwZW9mKGRmX2lyaXMkU3BlY2llcykKYGBgCgpgYGB7cn0KY2xhc3MoZGZfaXJpcyRTcGVjaWVzKQpgYGAKCkZvciBgZmFjdG9ycyA9IGZjdGAgc2VlIFt0aGUgUiBEb2N1bWVudF0oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL2Jhc2UvdmVyc2lvbnMvMy42LjIvdG9waWNzL2ZhY3Rvcikgb3IgYW4gZXhwbGFuYXRpb24gaW4gW0ZhY3RvciBpbiBSOiBDYXRlZ29yaWNhbCBWYXJpYWJsZSAmIENvbnRpbnVvdXMgVmFyaWFibGVzXShodHRwczovL3d3dy5ndXJ1OTkuY29tL3ItZmFjdG9yLWNhdGVnb3JpY2FsLWNvbnRpbnVvdXMuaHRtbCkuCgotLS0KCmBgYHtyfQp0eXBlb2YoZGZfaXJpcyRTZXBhbC5MZW5ndGgpCmNsYXNzKGRmX2lyaXMkU2VwYWwuTGVuZ3RoKQpgYGAKCgoqKlExLioqIFdoYXQgYXJlIHRoZSBkaWZmZXJlbmNlcyBvZmBkZl9pcmlzYCwgYHNsaWNlKGRmX2lyaXMsIDE6MTApYCBhbmQgYGdsaW1wc2UoZGZfaXJpcylgIGFib3ZlPwoKKipRMi4qKiBXaGF0IGFyZSB0aGUgZGlmZmVyZW5jZXMgb2ZgZGZfaXJpc2AsIGBzbGljZShkZl9pcmlzLCAxOjEwKWAgYW5kIGBnbGltcHNlKGRmX2lyaXMpYCBpbiB0aGUgY29uc29sZT8KCi0tLQoKIyMjIyBTdW1tYXJ5IG9mIHRoZSBEYXRhCgpUaGUgZm9sbG93aW5nIGlzIHZlcnkgY29udmVuaWVudCB0byBnZXQgdGhlIHN1bW1hcnkgaW5mb3JtYXRpb24gb2YgYSBkYXRhLgoKYGBge3J9CnN1bW1hcnkoZGZfaXJpcykKYGBgCgpNaW5pbXVtLCAxc3QgUXVhZHJhbnQgKDI1JSksICBNZWRpYW4sIE1lYW4sIDNyZCBRdWFkcmFudCAoNzUlKSwgTWF4aW11bSwgYW5kIHRoZSBjb3VudCBvZiBlYWNoIGZhY3Rvci4KCi0tLQoKIyMjIFZpc3VhbGl6aW5nIERhdGEKCiMjIyMgU2NhdHRlciBQbG90CgpXZSB1c2UgYGdncGxvdGAgdG8gZHJhdyBncmFwaHMuIFRoZSBzY2F0dGVyIHBsb3QgaXMgYSBwcm9qZWN0aW9uIG9mIGRhdGEgd2l0aCB0d28gdmFyaWFibGVzICR4JCBhbmQgJHkkLiAKYGBgCmdncGxvdChkYXRhID0gPGRhdGE+LCBhZXMoeCA9IDxjb2x1bW4gbmFtZSBmb3IgeD4sIHkgPSA8Y29sdW1uIG5hbWUgZm9yIHk+KSkgKwogIGdlb21fcG9pbnQoKQpgYGAKYGBgCmdncGxvdChkYXRhID0gZGZfaXJpcywgYWVzKHggPSBTZXBhbC5MZW5ndGgsIHkgPSBTZXBhbC5XaWR0aCkpICsKICBnZW9tX3BvaW50KCkKYGBgCgotLS0KCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjb21tZW50PUZBTFNFfQpnZ3Bsb3QoZGF0YSA9IGRmX2lyaXMsIGFlcyh4ID0gU2VwYWwuTGVuZ3RoLCB5ID0gU2VwYWwuV2lkdGgpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKLS0tCgojIyMjIFNjYXR0ZXIgUGxvdCB3aXRoIFtMYWJlbHNdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9sYWJzLmh0bWwpCgpBZGQgdGl0bGUgYW5kIGxhYmVscyBhZGRpbmcgYGxhYnMoKWAuIAoKYGBgCmdncGxvdChkYXRhID0gPGRhdGE+LCBhZXMoeCA9IDxjb2x1bW4gbmFtZSBmb3IgeD4sIHkgPSA8Y29sdW1uIG5hbWUgZm9yIHk+KSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJUaXRsZSIsIHggPSAiTGFiZWwgZm9yIHgiLCB5ID0gIkxhYmVsIGZvciB5IikKYGBgCi0tLQoKYGBge3J9CmdncGxvdChkYXRhID0gZGZfaXJpcywgYWVzKHggPSBTZXBhbC5MZW5ndGgsIHkgPSBTZXBhbC5XaWR0aCkpICsKICBnZW9tX3BvaW50KCkgKyAKICBsYWJzKHRpdGxlID0gIlNjYXR0ZXIgUGxvdCBvZiBTZXBhbCBEYXRhIG9mIElyaXMiLCB4ID0gIlNlcGFsIExlbmd0aCIsIHkgPSAiU2VwYWwgV2lkdGgiKQpgYGAKCi0tLQoKIyMjIyBTY2F0dGVyIFBsb3Qgd2l0aCBbQ29sb3JzXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvYWVzX2NvbG91cl9maWxsX2FscGhhLmh0bWwpCgpBZGQgZGlmZmVyZW50IGNvbG9ycyBhdXRvbWF0aWNhbGx5IHRvIGVhY2ggc3BlY2llcy4gQ2FuIHlvdSBzZWUgZWFjaCBncm91cD8KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRmX2lyaXMsIGFlcyh4ID0gU2VwYWwuTGVuZ3RoLCB5ID0gU2VwYWwuV2lkdGgsIGNvbG9yID0gU3BlY2llcykpICsKICBnZW9tX3BvaW50KCkKYGBgCgotLS0KCiMjIyMgU2NhdHRlciBQbG90IHdpdGggU2hhcGVzCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkZl9pcmlzLCBhZXMoeCA9IFNlcGFsLkxlbmd0aCwgeSA9IFNlcGFsLldpZHRoLCBzaGFwZSA9IFNwZWNpZXMpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKLS0tCgojIyMjIFtCb3hwbG90XShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2VvbV9ib3hwbG90Lmh0bWwpCgpUaGUgYm94cGxvdCBjb21wYWN0bHkgZGlzcGxheXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIGNvbnRpbnVvdXMgdmFyaWFibGUuIAoKYGBge3J9CmdncGxvdChkYXRhID0gZGZfaXJpcywgYWVzKHggPSBTcGVjaWVzLCB5ID0gU2VwYWwuTGVuZ3RoKSkgKwogIGdlb21fYm94cGxvdCgpCmBgYAoKLS0tCgojIyMjIFtIaXN0b2dyYW1dKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9nZW9tX2hpc3RvZ3JhbS5odG1sKQoKVmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YgYSBzaW5nbGUgY29udGludW91cyB2YXJpYWJsZSBieSBkaXZpZGluZyB0aGUgeCBheGlzIGludG8gYmlucyBhbmQgY291bnRpbmcgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gZWFjaCBiaW4uIEhpc3RvZ3JhbXMgKGdlb21faGlzdG9ncmFtKCkpIGRpc3BsYXkgdGhlIGNvdW50cyB3aXRoIGJhcnMuIAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRhID0gZGZfaXJpcywgYWVzKHggPSBTZXBhbC5MZW5ndGgpKSArCiAgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKCi0tLQoKQ2hhbmdlIHRoZSBudW1iZXIgb2YgYmlucyBieSBgYmlucyA9YCBgPG51bWJlcj5gLgoKYGBge3J9CmdncGxvdChkYXRhID0gZGZfaXJpcywgYWVzKHggPSBTZXBhbC5MZW5ndGgpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDEwKQpgYGAKCi0tLQoKIyMjIERhdGEgTW9kZWxpbmcgCgpQcm9mZXNzb3IgS2Fpem9qaSB3aWxsIGNvdmVyIHRoZSBtYXRoZW1hdGljYWwgbW9kZWxzIGFuZCBoeXBvdGhlc2lzIHRlc3RpbmdzLiAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZGF0YSA9IGRmX2lyaXMsIGFlcyh4ID0gU2VwYWwuTGVuZ3RoLCB5ID0gU2VwYWwuV2lkdGgpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKQpgYGAKCiMjIENvbW1lbnRzIG9uIFdlZWsgMgoKIyMjIyBIZWxwZnVsIFJlc291cmNlcwoKKiBDaGVhdCBTaGVldCBpbiBSU3R1ZGlvOiBodHRwczovL3d3dy5yc3R1ZGlvLmNvbS9yZXNvdXJjZXMvY2hlYXRzaGVldHMvICAKICAtIFtSU3R1ZGlvIElFRF0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3JzdHVkaW8vY2hlYXRzaGVldHMvbWFpbi9yc3R1ZGlvLWlkZS5wZGYpCiAgLSBbQmFzZSBSIENoZWF0IFNoZWV0XShodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9jaGVhdHNoZWV0cy9yYXcvbWFpbi9iYXNlLXIucGRmKQoqICdRdWljayBSJyBieSBEYXRhQ2FtcDogaHR0cHM6Ly93d3cuc3RhdG1ldGhvZHMubmV0L21hbmFnZW1lbnQKCiogW0FuIEludHJvZHVjdGlvbiB0byBSXShodHRwczovL2NyYW4ucnN0dWRpby5jb20pCgoKOjo6ey5hbGVydGJsb2NrfQojIyMjIFByYWN0aWN1bQoKKiBQb3NpdCBQcmltZXJzOiBUaGUgQmFzaWNzOiBodHRwczovL3Bvc2l0LmNsb3VkL2xlYXJuL3ByaW1lcnMvMQogIC0gQ29tcGxldGUgVmlzdWFsaXphdGlvbiBCYXNpY3MgYW5kIFByb2dyYW1taW5nIEJhc2ljcwoKLS0tCgojIyMjIEFzc2lnbm1lbnRzIC0gU2VlIE1vb2RsZQoKMS4gQXNzaWdubWVudCBXZWVrIDItMTogSW50cm9kdWN0aW9uIFBsdXMgRm9ydW0gIAogIC0gRHVlOiBUdWVzZGF5LCAyMCBEZWNlbWJlciAyMDIyLCAxMTo1OSBQTQoKMi4gQXNzaWdubWVudCBXZWVrIDItMjogUXVpeiAxIG9uIFIgQmFzaWNzIAogIC0gRHVlOiBUdWVzZGF5LCAyMCBEZWNlbWJlciAyMDIyLCAxMTo1OSBQTQoKOjo6CgoKIyMgU3dpcmw6IEFuIGludGVyYWN0aXZlIGxlYXJuaW5nIGVudmlyb25tZW50IGZvciBSIGFuZCBzdGF0aXN0aWNzCgoqIHtgc3dpcmxgfSB3ZWJzaXRlOiBodHRwczovL3N3aXJsc3RhdHMuY29tCiogSkhVIERhdGEgU2NpZW5jZSBpbiBjb3Vyc2VyYSB1c2VzIGBzd2lybGAgZm9yIGV4ZXJjaXNlcy4KCiMjIyBTd2lybCBDb3Vyc2VzCgoxLiBSIFByb2dyYW1taW5nOiBUaGUgYmFzaWNzIG9mIHByb2dyYW1taW5nIGluIFIKMi4gUmVncmVzc2lvbiBNb2RlbHM6IFRoZSBiYXNpY3Mgb2YgcmVncmVzc2lvbiBtb2RlbGluZyBpbiBSCjMuIFN0YXRpc3RpY2FsIEluZmVyZW5jZTogVGhlIGJhc2ljcyBvZiBzdGF0aXN0aWNhbCBpbmZlcmVuY2UgaW4gUgo0LiBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzOiBUaGUgYmFzaWNzIG9mIGV4cGxvcmluZyBkYXRhIGluIFIKCllvdSBjYW4gaW5zdGFsbCBvdGhlciBgc3dpcmxgIGNvdXJzZXMgYXMgd2VsbAoKKiBbU3dpcmwgQ291cnNlcyBPcmdhbml6ZWQgYnkgVGl0bGVdKGh0dHA6Ly9zd2lybHN0YXRzLmNvbS9zY24vdGl0bGUuaHRtbCkKKiBbU3dpcmwgQ291cnNlcyBPcmdhbml6ZWQgYnkgQXV0aG9y4oCZcyBOYW1lXShodHRwOi8vc3dpcmxzdGF0cy5jb20vc2NuL3N1cm5hbWUuaHRtbCkKKiBbR2l0aHViOiBzd2lybCBjb3Vyc2VzXShodHRwczovL2dpdGh1Yi5jb20vc3dpcmxkZXYvc3dpcmxfY291cnNlcyNzd2lybC1jb3Vyc2VzKSAKICAtIGBpbnN0YWxsX2NvdXJzZSgiQ291cnNlIE5hbWUgSGVyZSIpYAoKLS0tCgojIyMgSW5zdGFsbCBhbmQgU3RhcnQgU3dpcmwgQ291cnNlcwoKIyMjIyBUaHJlZSBTdGVwcyB0byBTdGFydCBTd2lybAoKYGBgCmluc3RhbGwucGFja2FnZXMoInN3aXJsIikgIyBPbmx5IHRoZSBmaXJzdCB0aW1lLgpsaWJyYXJ5KHN3aXJsKSAjIEV2ZXJ5dGltZSB5b3Ugc3RhcnQgc3dpcmwKc3dpcmwoKSAjIEV2ZXJ5dGltZSB5b3Ugc3RhcnQgb3IgcmVzdW1lIHN3aXJsCmBgYAoKIyMjIyBSIFByb2dyYW1taW5nOiBUaGUgYmFzaWNzIG9mIHByb2dyYW1taW5nIGluIFIKClxzY3JpcHRzaXplCmBgYAogMTogQmFzaWMgQnVpbGRpbmcgQmxvY2tzICAgICAgMjogV29ya3NwYWNlIGFuZCBGaWxlcyAgICAgMzogU2VxdWVuY2VzIG9mIE51bWJlcnMgICAgCiA0OiBWZWN0b3JzICAgICAgICAgICAgICAgICAgICA1OiBNaXNzaW5nIFZhbHVlcyAgICAgICAgICA2OiBTdWJzZXR0aW5nIFZlY3RvcnMgICAgICAKIDc6IE1hdHJpY2VzIGFuZCBEYXRhIEZyYW1lcyAgIDg6IExvZ2ljICAgICAgICAgICAgICAgICAgIDk6IEZ1bmN0aW9ucyAgICAgICAgICAgICAgIAoxMDogbGFwcGx5IGFuZCBzYXBwbHkgICAgICAgICAxMTogdmFwcGx5IGFuZCB0YXBwbHkgICAgICAxMjogTG9va2luZyBhdCBEYXRhICAgICAgICAgCjEzOiBTaW11bGF0aW9uICAgICAgICAgICAgICAgIDE0OiBEYXRlcyBhbmQgVGltZXMgICAgICAgIDE1OiBCYXNlIEdyYXBoaWNzICAgICAgICAgIApgYGAKCgojIyMjIFJlY29tbWVuZGVkIFNlY3Rpb25zIGluIE9yZGVyCgoxLCAzLCA0LCA1LCA2LCA3LCAxMiwgMTUsIDE0LCA4LCA5LCAxMCwgMTEsIDEzLCAyCgoqIFNlY3Rpb24gMiBkaXNjdXNzZXMgdGhlIGRpcmVjdG9yaWVzIGFuZCBmaWxlIHN5c3RlbXMgb2YgYSBjb21wdXRlcgoqIFNlY3Rpb25zIDksIDEwLCAxMSBhcmUgZm9yIHByb2dyYW1taW5nCgotLS0KCiMjIyMgQ29udHJvbGluZyBhIGBzd2lybGAgU2Vzc2lvbgoKKiAuLi4gIDwtLSBUaGF0J3MgeW91ciBjdWUgdG8gcHJlc3MgRW50ZXIgdG8gY29udGludWUKCiAgCiogWW91IGNhbiBleGl0IHN3aXJsIGFuZCByZXR1cm4gdG8gdGhlIFIgcHJvbXB0ICg+KSBhdCBhbnkgdGltZSBieSBwcmVzc2luZyB0aGUgRXNjIGtleS4KCiogSWYgeW91IGFyZSBhbHJlYWR5IGF0IHRoZSBwcm9tcHQsIHR5cGUgYnllKCkgdG8gZXhpdCBhbmQgc2F2ZSB5b3VyIHByb2dyZXNzLiBXaGVuIHlvdSBleGl0IHByb3Blcmx5LCB5b3UnbGwgc2VlIGEgc2hvcnQgbWVzc2FnZSBsZXR0aW5nIHlvdSBrbm93IHlvdSd2ZSBkb25lIHNvLgoKV2hlbiB5b3UgYXJlIGF0IHRoZSBSIHByb21wdCAoPik6CgoxLiBUeXBpbmcgc2tpcCgpIGFsbG93cyB5b3UgdG8gc2tpcCB0aGUgY3VycmVudCBxdWVzdGlvbi4KMi4gVHlwaW5nIHBsYXkoKSBsZXRzIHlvdSBleHBlcmltZW50IHdpdGggUiBvbiB5b3VyIG93bjsgc3dpcmwgd2lsbCBpZ25vcmUgd2hhdCB5b3UgZG8uLi4KMy4gVU5USUwgeW91IHR5cGUgbnh0KCkgd2hpY2ggd2lsbCByZWdhaW4gc3dpcmwncyBhdHRlbnRpb24uCjQuIFR5cGluZyBieWUoKSBjYXVzZXMgc3dpcmwgdG8gZXhpdC4gWW91ciBwcm9ncmVzcyB3aWxsIGJlIHNhdmVkLgo1LiBUeXBpbmcgbWFpbigpIHJldHVybnMgeW91IHRvIHN3aXJsJ3MgbWFpbiBtZW51Lgo2LiBUeXBpbmcgaW5mbygpIGRpc3BsYXlzIHRoZXNlIG9wdGlvbnMgYWdhaW4uCgotLS0KCiMjIyMgRmluYWwgUmVtYXJrCgpZb3Ugd2lsbCBlbmNvdW50ZXIgdGhlIG1lc3NhZ2UgbGlrZSDigJhXb3VsZCB5b3UgbGlrZSB0byByZWNlaXZlIGNyZWRpdCBmb3IgY29tcGxldGluZyB0aGlzIGNvdXJzZSBvbiBDb3Vyc2VyYS5vcmc/4oCZIGF0IHRoZSBlbmQgb2YgZWFjaCBjb3Vyc2UuIFRoaXMgaXMgZm9yIGBjb3Vyc2VyYWAgY291cnNlcy4gU2VsZWN0ICdOTycuIAoKCgojIyBNb3JlIG9uIFIgU2NyaXB0OiBFeGFtcGxlcwoKIyMjIFIgU2NyaXB0cyBpbiBNb29kbGUKCiogYmFzaWNzLlIKKiBjb3JvbmF2aXJ1cy5SCgoxLiBDb3B5IGEgc2NyaXB0IGluIE1vb2RsZTogX3tmaWxlIG5hbWV9LlJfCjIuIEluIFJTdHVkaW8gKFdvcmtzcGFjZSBpbiBSU3R1ZGlvLmNsb3VkLCBQcm9qZWN0IGluIFJTdHVkaW8pIGNob29zZSBGaWxlID4gTmV3IEZpbGUgPiBSIFNjcmlwdCBhbmQgcGFzdGUgaXQuCjMuIENob29zZSBGaWxlID4gU2F2ZSB3aXRoIGEgbmFtZTsgZS5nLiBfe2ZpbGUgbmFtZXN9XyAoLlIgd2lsbCBiZSBhZGRlZCBhdXRvbWF0aWNhbGx5KQoKLS0tCgojIyMgYGJhc2ljcy5SYAoKVGhlIHNjcmlwdCB3aXRoIHRoZSBvdXRwdXRzLgoKYGBge3IgYmFzaWNzLCBldmFsPUZBTFNFfQojIyMjIyMjIyMjIyMjIyMjIwojCiMgYmFzaWNzLlIKIwojIyMjIyMjIyMjIyMjIyMjCiMgJ1F1aWNrIFInIGJ5IERhdGFDYW1wIG1heSBiZSBhIGhhbmR5IHJlZmVyZW5jZTogCiMgICAgIGh0dHBzOi8vd3d3LnN0YXRtZXRob2RzLm5ldC9tYW5hZ2VtZW50L2luZGV4Lmh0bWwKIyBDaGVhdCBTaGVldCBhdCBSU3R1ZGlvOiBodHRwczovL3d3dy5yc3R1ZGlvLmNvbS9yZXNvdXJjZXMvY2hlYXRzaGVldHMvCiMgQmFzZSBSIENoZWF0IFNoZWV0OiBodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9jaGVhdHNoZWV0cy9yYXcvbWFpbi9iYXNlLXIucGRmCiMgVG8gZXhlY3V0ZSB0aGUgbGluZTogQ29udHJvbCArIEVudGVyIChXaW5kb3cgYW5kIExpbnV4KSwgQ29tbWFuZCArIEVudGVyIChNYWMpCiMjIHRyeSB5b3VyIGV4cGVyaW1lbnRzIG9uIHRoZSBjb25zb2xlCgojIyBjYWxjdWxhdG9yCgozICsgNwoKIyMjICssIC0sICosIC8sIF4gKG9yICoqKSwgJSUsICUvJQoKMyArIDEwIC8gMgoKM14yCgoyXjMKCjIqMioyCgojIyMgYXNzaWdubWVudDogPC0sICg9LCAtPiwgYXNzaWduKCkpIAoKeCA8LSA1Cgp4IAoKIyMjIyBvYmplY3RfbmFtZSA8LSB2YWx1ZSwgJzwtJyBzaG9ydGN1dDogQWx0IChvcHRpb24pICsgJy0nIChoeXBoZW4gb3IgbWludXMpIAojIyMjIE9iamVjdCBuYW1lcyBtdXN0IHN0YXJ0IHdpdGggYSBsZXR0ZXIgYW5kIGNhbiBvbmx5IGNvbnRhaW4gbGV0dGVyLCBudW1iZXJzLCBfIGFuZCAuCgp0aGlzX2lzX2FfbG9uZ19uYW1lIDwtIDVeMwoKdGhpc19pc19hX2xvbmdfbmFtZQoKY2hhcl9uYW1lIDwtICJXaGF0IGlzIHlvdXIgbmFtZT8iCgpjaGFyX25hbWUKCiMjIyMgVXNlICd0YWIgY29tcGxldGlvbicgYW5kICd1cCBhcnJvdycKCiMjIyBscygpOiBsaXN0IG9mIGFsbCBhc3NpZ25tZW50cwoKbHMoKQpscy5zdHIoKQoKIyMjIyBjaGVjayBFbnZpcm9ubWVudCBpbiB0aGUgdXBwZXIgcmlnaHQgcGFuZQoKIyMjIChhdG9taWMpIHZlY3RvcnMKCjU6MTAKCmEgPC0gc2VxKDUsMTApCgphCgpiIDwtIDU6MTAKCmlkZW50aWNhbChhLGIpCgpzZXEoNSwxMCwyKSAjIHNhbWUgYXMgc2VxKGZyb20gPSA1LCB0byA9IDEwLCBieSA9IDIpCgpjMSA8LSBzZXEoMCwxMDAsIGJ5ID0gMTApCgpjMiA8LSBzZXEoMCwxMDAsIGxlbmd0aC5vdXQgPSAxMCkKCmMxCgpjMgoKbGVuZ3RoKGMxKQoKIyMjIyA/IHNlcSAgID8gbGVuZ3RoICAgPyBpZGVudGljYWwKCihkaWUgPC0gMTo2KQoKemVyb19vbmUgPC0gYygwLDEpICMgc2FtZSBhcyAwOjEKCmRpZSArIHplcm9fb25lICMgYygxLDIsMyw0LDUsNikgKyBjKDAsMSkuIHJlLXVzZQoKZDEgPC0gcmVwKDE6MywyKSAjIHJlcGVhdAoKCmQxCgpkaWUgPT0gZDEKCmQyIDwtIGFzLmNoYXJhY3RlcihkaWUgPT0gZDEpCgpkMgoKZDMgPC0gYXMubnVtZXJpYyhkaWUgPT0gZDEpCgpkMwoKIyMjIGNsYXNzKCkgZm9yIGNsYXNzIGFuZCB0eXBlb2YoKSBmb3IgbW9kZQojIyMgY2xhc3Mgb2YgdmVjdG9yczogbnVtZXJpYywgY2hhcmN0ZXJzLCBsb2dpY2FsCiMjIyB0eXBlcyBvZiB2ZWN0b3JzOiBkb3VibGVzLCBpbnRlZ2VycywgY2hhcmFjdGVycywgbG9naWNhbHMgKGNvbXBsZXggYW5kIHJhdykKCnR5cGVvZihkMSk7IGNsYXNzKGQxKQoKdHlwZW9mKGQyKTsgY2xhc3MoZDIpCgp0eXBlb2YoZDMpOyBjbGFzcyhkMykKCnNxcnQoMikKCnNxcnQoMileMgoKc3FydCgyKV4yIC0gMgoKdHlwZW9mKHNxcnQoMikpCgp0eXBlb2YoMikKCnR5cGVvZigyTCkKCjUgPT0gYyg1KQoKbGVuZ3RoKDUpCgojIyMgU3Vic2V0dGluZwoKKEFfWiA8LSBMRVRURVJTKQoKQV9GIDwtIEFfWlsxOjZdCgpBX0YKCkFfRlszXQoKQV9GW2MoMyw1KV0KCmxhcmdlIDwtIGRpZSA+IDMKCmxhcmdlCgpldmVuIDwtIGRpZSAlaW4lIGMoMiw0LDYpCgpldmVuCgpBX0ZbbGFyZ2VdCgpBX0ZbZXZlbl0KCkFfRltkaWUgPCA0XQoKIyMjIENvbXBhcmUgZGYgd2l0aCBkZjEgPC0gZGF0YS5mcmFtZShudW1iZXIgPSBkaWUsIGFscGhhYmV0ID0gQV9GKQpkZiA8LSBkYXRhLmZyYW1lKG51bWJlciA9IGRpZSwgYWxwaGFiZXQgPSBBX0YsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCmRmCgpkZiRudW1iZXIKCmRmJGFscGhhYmV0CgpkZlszLDJdCgpkZls0LDFdCgpkZlsxXQoKY2xhc3MoZGZbMV0pCgpjbGFzcyhkZltbMV1dKQoKaWRlbnRpY2FsKGRmW1sxXV0sIGRpZSkKCmlkZW50aWNhbChkZlsxXSxkaWUpCgojIyMjIyMjIyMjIyMjIyMjIyMjIwojIFRoZSBGaXJzdCBFeGFtcGxlCiMjIyMjIyMjIyMjIyMjIyMjIyMjCgpwbG90KGNhcnMpCgojIEhlbHAKCj8gY2FycwoKIyBjYXJzIGlzIGluIHRoZSAnZGF0YXNldHMnIHBhY2thZ2UKCmRhdGEoKQoKIyBoZWxwKGNhcnMpIGRvZXMgdGhlIHNhbWUgYXMgPyBjYXJzCiMgWW91IGNhbiB1c2UgSGVscCB0YWIgaW4gdGhlIHJpZ2h0IGJvdHRvbSBwYW5lCgpoZWxwKHBsb3QpCj8gcGFyCgpoZWFkKGNhcnMpCgpzdHIoY2FycykKCnN1bW1hcnkoY2FycykKCnggPC0gY2FycyRzcGVlZAp5IDwtIGNhcnMkZGlzdAoKbWluKHgpCm1lYW4oeCkKcXVhbnRpbGUoeCkKCnBsb3QoY2FycykKCmFibGluZShsbShjYXJzJGRpc3QgfiBjYXJzJHNwZWVkKSkKCnN1bW1hcnkobG0oY2FycyRkaXN0IH4gY2FycyRzcGVlZCkpCgpib3hwbG90KGNhcnMpCgpoaXN0KGNhcnMkc3BlZWQpCmhpc3QoY2FycyRkaXN0KQpoaXN0KGNhcnMkZGlzdCwgYnJlYWtzID0gc2VxKDAsMTIwLCAxMCkpCmBgYAoKLS0tCgojIyMgY29yb25hdmlydXMuUgoKVGhlIHNjcmlwdCBhbmQgaXRzIG91dHB1dHMuCl9fY29yb25hdmlydXMuY3N2X18gaXMgdmVyeSBsYXJnZQoKCmBgYHtyIGNhc2ggPSBUUlVFLCBldmFsPUZBTFNFfQojIGh0dHBzOi8vY29yb25hdmlydXMuamh1LmVkdS9tYXAuaHRtbAojIEpIVSBDb3ZpZC0xOSBnbG9iYWwgdGltZSBzZXJpZXMgZGF0YQojIFNlZSBSIHBha2FnZSBjb3JvbmF2aXJ1cyBhdDogaHR0cHM6Ly9naXRodWIuY29tL1JhbWlLcmlzcGluL2Nvcm9uYXZpcnVzCiMgRGF0YSB0YWtlbiBmcm9tOiBodHRwczovL2dpdGh1Yi5jb20vUmFtaUtyaXNwaW4vY29yb25hdmlydXMvdHJlZS9tYXN0ZXIvY3N2CiMgTGFzdCBVcGRhdGVkClN5cy5EYXRlKCkKCiMjIERvd25sb2FkIGFuZCByZWFkIGNzdiAoY29tbWEgc2VwYXJhdGVkIHZhbHVlKSBmaWxlCmNvcm9uYXZpcnVzIDwtIHJlYWQuY3N2KCJodHRwczovL2dpdGh1Yi5jb20vUmFtaUtyaXNwaW4vY29yb25hdmlydXMvcmF3L21hc3Rlci9jc3YvY29yb25hdmlydXMuY3N2IikKIyB3cml0ZS5jc3YoY29yb25hdmlydXMsICJkYXRhL2Nvcm9uYXZpcnVzLmNzdiIpCgojIyBTdW1tYXJpZXMgYW5kIHN0cnVjdHVyZXMgb2YgdGhlIGRhdGEKaGVhZChjb3JvbmF2aXJ1cykKc3RyKGNvcm9uYXZpcnVzKQpjb3JvbmF2aXJ1cyRkYXRlIDwtIGFzLkRhdGUoY29yb25hdmlydXMkZGF0ZSkKc3RyKGNvcm9uYXZpcnVzKQoKcmFuZ2UoY29yb25hdmlydXMkZGF0ZSkKdW5pcXVlKGNvcm9uYXZpcnVzJGNvdW50cnkpCnVuaXF1ZShjb3JvbmF2aXJ1cyR0eXBlKQoKIyMgU2V0IENvdW50cnkKQ09VTlRSWSA8LSAiSmFwYW4iCmRmMCA8LSBjb3JvbmF2aXJ1c1tjb3JvbmF2aXJ1cyRjb3VudHJ5ID09IENPVU5UUlksXQpoZWFkKGRmMCkKdGFpbChkZjApCihwb3AgPC0gZGYwJHBvcHVsYXRpb25bMV0pCmRmIDwtIGRmMFtjKDEsNiw3LDEzKV0Kc3RyKGRmKQpoZWFkKGRmKQojIyMgYWx0ZXJuYXRpdmVseSwKaGVhZChkZjBbYygiZGF0ZSIsICJ0eXBlIiwgImNhc2VzIiwgInBvcHVsYXRpb24iKV0pCiMjIwoKIyMgU2V0IHR5cGVzCmRmX2NvbmZpcm1lZCA8LSBkZltkZiR0eXBlID09ICJjb25maXJtZWQiLF0KZGZfZGVhdGggPC0gZGZbZGYkdHlwZSA9PSAiZGVhdGgiLF0KZGZfcmVjb3ZlcnkgPC0gZGZbZGYkZGF0YV90eXBlID09ICJyZWNvdmVyeSIsXQpoZWFkKGRmX2NvbmZpcm1lZCkKaGVhZChkZl9kZWF0aCkKaGVhZChkZl9yZWNvdmVyeSkKCiMjIEhpc3RvZ3JhbQpwbG90KGRmX2NvbmZpcm1lZCRkYXRlLCBkZl9jb25maXJtZWQkY2FzZXMsIHR5cGUgPSAiaCIpCnBsb3QoZGZfZGVhdGgkZGF0ZSwgZGZfZGVhdGgkY2FzZXMsIHR5cGUgPSAiaCIpCiMgcGxvdChkZl9yZWNvdmVyZWQkZGF0ZSwgZGZfcmVjb3ZlcmVkJGNhc2VzLCB0eXBlID0gImgiKSAjIG5vIGRhdGEgZm9yIHJlY292ZXJ5CgojIyBTY2F0dGVyIHBsb3QgYW5kIGNvcnJlbGF0aW9uCnBsb3QoZGZfY29uZmlybWVkJGNhc2VzLCBkZl9kZWF0aCRjYXNlcywgdHlwZSA9ICJwIikKY29yKGRmX2NvbmZpcm1lZCRjYXNlcywgZGZfZGVhdGgkY2FzZXMpCgoKIyMgSW4gYWRkaXRpb24gc2V0IGEgcGVyaW9kCnN0YXJ0X2RhdGUgPC0gYXMuRGF0ZSgiMjAyMS0wNy0wMSIpCmVuZF9kYXRlIDwtIFN5cy5EYXRlKCkgCmRmX2RhdGUgPC0gZGZbZGYkZGF0ZSA+PXN0YXJ0X2RhdGUgJiBkZiRkYXRlIDw9IGVuZF9kYXRlLF0KIyMKCiMjIFNldCB0eXBlcwpkZl9kYXRlX2NvbmZpcm1lZCA8LSBkZl9kYXRlW2RmX2RhdGUkdHlwZSA9PSAiY29uZmlybWVkIixdCmRmX2RhdGVfZGVhdGggPC0gZGZfZGF0ZVtkZl9kYXRlJHR5cGUgPT0gImRlYXRoIixdCmRmX2RhdGVfcmVjb3ZlcnkgPC0gZGZfZGF0ZVtkZl9kYXRlJGRhdGFfdHlwZSA9PSAicmVjb3ZlcnkiLF0KaGVhZChkZl9kYXRlX2NvbmZpcm1lZCkKaGVhZChkZl9kYXRlX2RlYXRoKQpoZWFkKGRmX2RhdGVfcmVjb3ZlcnkpCgojIyBIaXN0b2dyYW0KcGxvdChkZl9kYXRlX2NvbmZpcm1lZCRkYXRlLCBkZl9kYXRlX2NvbmZpcm1lZCRjYXNlcywgdHlwZSA9ICJoIikKcGxvdChkZl9kYXRlX2RlYXRoJGRhdGUsIGRmX2RhdGVfZGVhdGgkY2FzZXMsIHR5cGUgPSAiaCIpCiMgcGxvdChkZl9kYXRlX3JlY292ZXJlZCRkYXRlLCBkZl9kYXRlX3JlY292ZXJlZCRjYXNlcywgdHlwZSA9ICJoIikgIyBubyBkYXRhIGZvciByZWNvdmVyeQoKcGxvdChkZl9kYXRlX2NvbmZpcm1lZCRjYXNlcywgZGZfZGF0ZV9kZWF0aCRjYXNlcywgdHlwZSA9ICJwIikKY29yKGRmX2RhdGVfY29uZmlybWVkJGNhc2VzLCBkZl9kYXRlX2RlYXRoJGNhc2VzKQoKIyMjIFEwLiBDaGFuZ2UgdGhlIHZhbHVlcyBvZiB0aGUgbG9jYXRpb24gYW5kIHRoZSBwZXJpb2QgYW5kIHNlZSB0aGUgb3V0Y29tZXMuCiMjIyBRMS4gV2hhdCBpcyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBkZl9jb25maXJtZWQkY2FzZXMgYW5kIGRmX2RlYXRoJGNhc2VzPwojIyMgUTIuIERvIHdlIGhhdmUgYSBsYXJnZXIgY29ycmVsYXRpb24gdmFsdWUgaWYgd2Ugc2hpZnQgdGhlIGRhdGVzIHRvIGltcGxlbWVudCB0aGUgdGltZS1sYWc/CiMjIyBRMy4gRG8geW91IGhhdmUgYW55IG90aGVyIHF1ZXN0aW9ucyB0byBleHBsb3JlPwoKIyMjIyBFeHRyYQpwbG90KGRmX2NvbmZpcm1lZCRkYXRlLCBkZl9jb25maXJtZWQkY2FzZXMsIHR5cGUgPSAiaCIsIAogICAgIG1haW4gPSBwYXN0ZSgiQ29tZmlybWVkIENhc2VzIGluIixDT1VOVFJZKSwgCiAgICAgeGxhYiA9ICJEYXRlIiwgeWxhYiA9ICJOdW1iZXIgb2YgQ2FzZXMiKQpgYGAKCjo6OgoKIyMgYGdhcG1pbmRlcmAgUGFja2FnZQoKIyMjIEhhbnMgUm9zbGluZyAoMTk0OCDigJMgMjAxNykKCj4gSGFucyBSb3NsaW5nIHdhcyBhIFN3ZWRpc2ggcGh5c2ljaWFuLCBhY2FkZW1pYywgYW5kIHB1YmxpYyBzcGVha2VyLiBIZSB3YXMgYSBwcm9mZXNzb3Igb2YgaW50ZXJuYXRpb25hbCBoZWFsdGggYXQgS2Fyb2xpbnNrYSBJbnN0aXR1dGVbNF0gYW5kIHdhcyB0aGUgY28tZm91bmRlciBhbmQgY2hhaXJtYW4gb2YgdGhlIEdhcG1pbmRlciBGb3VuZGF0aW9uLCB3aGljaCBkZXZlbG9wZWQgdGhlIFRyZW5kYWx5emVyIHNvZnR3YXJlIHN5c3RlbS4gKFt3aWtpcGVkaWFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0hhbnNfUm9zbGluZykpCgoqIEJvb2tzOiAKICAtIEZhY3RmdWxuZXNzOiBUZW4gUmVhc29ucyBXZSdyZSBXcm9uZyBBYm91dCBUaGUgV29ybGQgLSBBbmQgV2h5IFRoaW5ncyBBcmUgQmV0dGVyIFRoYW4gWW91IFRoaW5rLCAyMDE4CiAgLSBIb3cgSSBMZWFybmVkIHRvIFVuZGVyc3RhbmQgdGhlIFdvcmxkOiBBIE1lbW9pciwgMjAyMAoqIEdhcG1pbmRlcjogaHR0cHM6Ly93d3cuZ2FwbWluZGVyLm9yZwogIC0gW1lvdSBhcmUgcHJvYmFibHkgd3JvbmcgYWJvdXQ6IFVwZ3JhZGUgWW91ciBXb3JsZCBWaWV3XShodHRwczovL3VwZ3JhZGVyLmdhcG1pbmRlci5vcmcpCiAgLSBbQnViYmxlIENoYXJ0XShodHRwczovL3d3dy5nYXBtaW5kZXIub3JnL3Rvb2xzLyMkc3RhdGUkdGltZSR2YWx1ZT0yMDIwOzsmY2hhcnQtdHlwZT1idWJibGVzKTogSW5jb21lIHZzIExpZmUgRXhwZWN0YW5jeSBvdmVyIHRpbWUsIDE4MDAgLSAyMDIwCiAgICArIEhvdyBtYW55IHZhcmlhYmxlcz8KKiBWaWRlb3M6IFtUaGUgYmVzdCBzdGF0cyB5b3XigJl2ZSBldmVyIHNlZW4sIEhhbnMgUm9zbGluZ10oaHR0cDovL3d3dy5lZHRlY2guZXZlbnRzL3RoZS1iZXN0LXN0YXRzLXlvdXZlLWV2ZXItc2Vlbi1oYW5zLXJvc2xpbmcvKQoKLS0tCgojIyMgRmFjdGZ1bG5lc3MgaXMgLi4uIFxoZmlsbCBfRnJvbSB0aGUgYm9va18KCnJlY29nbml6aW5nIHdoZW4gYSBkZWNpc2lvbiBmZWVscyB1cmdlbnQgYW5kIHJlbWVtYmVyaW5nIHRoYXQgaXQgcmFyZWx5IGlzLgoKVG8gY29udHJvbCB0aGUgdXJnZW5jeSBpbnN0aW5jdCwgdGFrZSBzbWFsbCBzdGVwcy4KCiogVGFrZSBhIGJyZWF0aC4gV2hlbiB5b3VyIHVyZ2VuY3kgaW5zdGluY3QgaXMgdHJpZ2dlcmVkLCB5b3VyIG90aGVyIGluc3RpbmN0cyBraWNrIGluIGFuZCB5b3VyIGFuYWx5c2lzIHNodXRzIGRvd24uIEFzayBmb3IgbW9yZSB0aW1lIGFuZCBtb3JlIGluZm9ybWF0aW9uLiBJdOKAmXMgcmFyZWx5IG5vdyBvciBuZXZlciBhbmQgaXTigJlzIHJhcmVseSBlaXRoZXIvb3IuCiogSW5zaXN0IG9uIHRoZSBkYXRhLiBJZiBzb21ldGhpbmcgaXMgdXJnZW50IGFuZCBpbXBvcnRhbnQsIGl0IHNob3VsZCBiZSBtZWFzdXJlZC4gQmV3YXJlIG9mIGRhdGEgdGhhdCBpcyByZWxldmFudCBidXQgaW5hY2N1cmF0ZSwgb3IgYWNjdXJhdGUgYnV0IGlycmVsZXZhbnQuIE9ubHkgcmVsZXZhbnQgYW5kIGFjY3VyYXRlIGRhdGEgaXMgdXNlZnVsLgoqIEJld2FyZSBvZiBmb3J0dW5lLXRlbGxlcnMuIEFueSBwcmVkaWN0aW9uIGFib3V0IHRoZSBmdXR1cmUgaXMgdW5jZXJ0YWluLiBCZSB3YXJ5IG9mIHByZWRpY3Rpb25zIHRoYXQgZmFpbCB0byBhY2tub3dsZWRnZSB0aGF0LiBJbnNpc3Qgb24gYSBmdWxsIHJhbmdlIG9mIHNjZW5hcmlvcywgbmV2ZXIganVzdCB0aGUgYmVzdCBvciB3b3JzdCBjYXNlLiBBc2sgaG93IG9mdGVuIHN1Y2ggcHJlZGljdGlvbnMgaGF2ZSBiZWVuIHJpZ2h0IGJlZm9yZS4KKiBCZSB3YXJ5IG9mIGRyYXN0aWMgYWN0aW9uLiBBc2sgd2hhdCB0aGUgc2lkZSBlZmZlY3RzIHdpbGwgYmUuIEFzayBob3cgdGhlIGlkZWEgaGFzIGJlZW4gdGVzdGVkLiBTdGVwLWJ5LXN0ZXAgcHJhY3RpY2FsIGltcHJvdmVtZW50cywgYW5kIGV2YWx1YXRpb24gb2YgdGhlaXIgaW1wYWN0LCBhcmUgbGVzcyBkcmFtYXRpYyBidXQgdXN1YWxseSBtb3JlIGVmZmVjdGl2ZS4KCi0tLQoKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygiZ2FwbWluZGVyIikKbGlicmFyeShnYXBtaW5kZXIpCmBgYApgYGB7cn0KZGYgPC0gZ2FwbWluZGVyCmRmCmBgYAoKLS0tCgpgYGB7cn0KZ2xpbXBzZShkZikKYGBgCgotLS0KCmBgYHtyfQpzdW1tYXJ5KGRmKQpgYGAKCi0tLQoKIyMjIFF1ZXN0aW9ucwoKKiBMaXN0IHF1ZXN0aW9ucyBiYXNlZCBvbiB0aGlzIGRhdGEuCiogV2hhdCBkbyB5b3Ugd2FudCB0byBzZWU/IAoqIFdoYXQga2luZCBvZiBjaGFydCBkbyB5b3Ugd2FudCB0byBjb25zdHJ1Y3Q/CgoKIyMgUmV2aWV3IHstfQoKKiBSIG9uIFIgU3R1ZGlvL1Bvc2l0IENsb3VkIChSU3R1ZGlvIENsb3VkKQoqIFRocmVlIHdheXMgdG8gcnVuIGNvZGVzCiAgMS4gQ29uc29sZQogIDIuIFIgU2NyaXB0CiAgMy4gQ29kZSBDaHVuayBpbiBSIE5vdGVib29rCiogUGFja2FnZXMKICAxLiBgdGlkeXZlcnNlYAogIDIuIGBybWFya2Rvd25gCiAgMy4gYGdhcG1pbmRlcmAKICAKYGBge3IgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2FwbWluZGVyKQpsaWJyYXJ5KFdESSkKYGBgCgoKLS0tCgojIyMjIEVEQSAoQSBkaWFncmFtIGZyb20gUjREUyBieSBILlcuIGFuZCBHLkcuKSB7LX0KCiFbRURBIGZyb20gcjRkc10oZGF0YS9kYXRhLXNjaWVuY2UucG5nKQoKKipUb2RheSoqOiBSIE1hcmtkb3duIGFuZCBgZHBseXJgCgojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgSUkKCiMjIFIgTWFya2Rvd24KCldoYXQgaXMgUiBNYXJrZG93bjogaHR0cHM6Ly92aW1lby5jb20vMTc4NDg1NDE2CgoqIENvZGUgQ2h1bmtzCiogVGV4dAoqIFlBTUwgTWV0YWRhdGEKCi0tLQoKIyMjIFdoYXQgaXMgUiBNYXJrZG93biBhbmQgUiBOb3RlYm9vawoKUiBNYXJrZG93biBwcm92aWRlcyBhbiBhdXRob3JpbmcgZnJhbWV3b3JrIGZvciBkYXRhIHNjaWVuY2UuIFlvdSBjYW4gdXNlIGEgc2luZ2xlIFIgTWFya2Rvd24gZmlsZSB0byBib3RoCgoqIHNhdmUgYW5kIGV4ZWN1dGUgY29kZQoqIGdlbmVyYXRlIGhpZ2ggcXVhbGl0eSByZXBvcnRzIHRoYXQgY2FuIGJlIHNoYXJlZCB3aXRoIGFuIGF1ZGllbmNlCgpSIE5vdGVib29rcyBhcmUgYW4gaW1wbGVtZW50YXRpb24gb2YgTGl0ZXJhdGUgUHJvZ3JhbW1pbmcgdGhhdCBhbGxvd3MgZm9yIGRpcmVjdCBpbnRlcmFjdGlvbiB3aXRoIFIgd2hpbGUgcHJvZHVjaW5nIGEgcmVwcm9kdWNpYmxlIGRvY3VtZW50IHdpdGggcHVibGljYXRpb24tcXVhbGl0eSBvdXRwdXQuCgpBbiAqKlIgTm90ZWJvb2sqKiBpcyBhbiBSIE1hcmtkb3duIGRvY3VtZW50IF93aXRoIGNodW5rcyB0aGF0IGNhbiBiZSBleGVjdXRlZCBpbmRlcGVuZGVudGx5IGFuZCBpbnRlcmFjdGl2ZWx5LCB3aXRoIG91dHB1dCB2aXNpYmxlIGltbWVkaWF0ZWx5IGJlbmVhdGggdGhlIGlucHV0Xy4KCihSZWZlcmVuY2U6IFtSIE1hcmtkb3duOiBUaGUgRGVmaW5pdGl2ZSBHdWlkZSwgMy4yIE5vdGVib29rXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vbm90ZWJvb2suaHRtbCkpCgotLS0KCiMjIyMgVHdvIEdvb2RpZXMKCiogKipJbXBvcnRhbnQqKjogSW1wbGVtZW50YXRpb24gb2YgUmVwcm9kdWNpYmxlIFJlc2VhcmNoIGFuZCBMaXRlcmF0ZSBQcm9ncmFtbWluZwoKKiAqKlVzZWZ1bCoqIHRvIFJlbmRlciBpbnRvIFZhcmlvdXMgRm9ybWF0czogUiBOb3RlYm9vayAoSFRNTCksIFIgTWFya2Rvd24gKEhUTUwpLCBQREYsIE1TIFdvcmQsIE1TIFBvd2VycG9pbnQsIElvc2xpZGVzIFByZXNlbnRhdGlvbiAoSFRNTCksIFNsaWR5IFByZXNlbnRhdGlvbiAoSFRNTCksIEJlYW1lciBQcmVzZW50YXRpb24gKFBERiksIGV0Yy4KCi0tLQoKIyMjIFJlcHJvZHVjaWJsZSBSZXNlYXJjaCBhbmQgTGl0ZXJhdGUgUHJvZ3JhbW1pbmcKCiMjIyMgTGl0ZXJhdGUgUHJvZ3JhbW1pbmcgYnkgRC4gS251dGgKCkxpdGVyYXRlIHByb2dyYW1taW5nIGlzIGFuIGFwcHJvYWNoIHRvIHByb2dyYW1taW5nIGludHJvZHVjZWQgYnkgRG9uYWxkIEtudXRoIGluIHdoaWNoIGEgcHJvZ3JhbSBpcyBnaXZlbiBhcyBhbiBleHBsYW5hdGlvbiBvZiB0aGUgcHJvZ3JhbSBsb2dpYyBpbiBhIG5hdHVyYWwgbGFuZ3VhZ2UsIHN1Y2ggYXMgRW5nbGlzaCwgaW50ZXJzcGVyc2VkIHdpdGggc25pcHBldHMgb2YgbWFjcm9zIGFuZCB0cmFkaXRpb25hbCBzb3VyY2UgY29kZSwgZnJvbSB3aGljaCBhIGNvbXBpbGFibGUgc291cmNlIGNvZGUgY2FuIGJlIGdlbmVyYXRlZAoKIyMjIyBbRC4gS251dGhdKGh0dHBzOi8vd3d3LmJyYWlueXF1b3RlLmNvbS9xdW90ZXMvZG9uYWxkX2tudXRoXzE4MTYzNCkKTGV0IHVzIGNoYW5nZSBvdXIgdHJhZGl0aW9uYWwgYXR0aXR1ZGUgdG8gdGhlIGNvbnN0cnVjdGlvbiBvZiBwcm9ncmFtczogSW5zdGVhZCBvZiBpbWFnaW5pbmcgdGhhdCBvdXIgbWFpbiB0YXNrIGlzIHRvIGluc3RydWN0IGEgY29tcHV0ZXIgd2hhdCB0byBkbywgbGV0IHVzIGNvbmNlbnRyYXRlIHJhdGhlciBvbiBleHBsYWluaW5nIHRvIGh1bWFuIGJlaW5ncyB3aGF0IHdlIHdhbnQgYSBjb21wdXRlciB0byBkby4KCi0tLQoKIyMjIyBSZXByb2R1Y2libGUgUmVzZWFyY2ggLSBRdW90ZSBmcm9tIGEgW0NvdXJzZXJhIENvdXJzZV0oaHR0cHM6Ly93d3cuY291cnNlcmEub3JnL2xlYXJuL3JlcHJvZHVjaWJsZS1yZXNlYXJjaCkKClJlcHJvZHVjaWJsZSByZXNlYXJjaCBpcyB0aGUgaWRlYSB0aGF0IGRhdGEgYW5hbHlzZXMsIGFuZCBtb3JlIGdlbmVyYWxseSwgc2NpZW50aWZpYyBjbGFpbXMsIGFyZSBwdWJsaXNoZWQgd2l0aCB0aGVpciBkYXRhIGFuZCBzb2Z0d2FyZSBjb2RlIHNvIHRoYXQgb3RoZXJzIG1heSB2ZXJpZnkgdGhlIGZpbmRpbmdzIGFuZCBidWlsZCB1cG9uIHRoZW0uICBUaGUgbmVlZCBmb3IgcmVwcm9kdWNpYmlsaXR5IGlzIGluY3JlYXNpbmcgZHJhbWF0aWNhbGx5IGFzIGRhdGEgYW5hbHlzZXMgYmVjb21lIG1vcmUgY29tcGxleCwgaW52b2x2aW5nIGxhcmdlciBkYXRhc2V0cyBhbmQgbW9yZSBzb3BoaXN0aWNhdGVkIGNvbXB1dGF0aW9ucy4gUmVwcm9kdWNpYmlsaXR5IGFsbG93cyBmb3IgcGVvcGxlIHRvIGZvY3VzIG9uIHRoZSBhY3R1YWwgY29udGVudCBvZiBhIGRhdGEgYW5hbHlzaXMsIHJhdGhlciB0aGFuIG9uIHN1cGVyZmljaWFsIGRldGFpbHMgcmVwb3J0ZWQgaW4gYSB3cml0dGVuIHN1bW1hcnkuIEluIGFkZGl0aW9uLCByZXByb2R1Y2liaWxpdHkgbWFrZXMgYW4gYW5hbHlzaXMgbW9yZSB1c2VmdWwgdG8gb3RoZXJzIGJlY2F1c2UgdGhlIGRhdGEgYW5kIGNvZGUgdGhhdCBhY3R1YWxseSBjb25kdWN0ZWQgdGhlIGFuYWx5c2lzIGFyZSBhdmFpbGFibGUuIAoKLS0tCgojIyMjIFIgTWFya2Rvd24gd29ya2Zsb3csIFtSIGZvciBEYXRhIFNjaWVuY2VdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovci1tYXJrZG93bi13b3JrZmxvdy5odG1sI3ItbWFya2Rvd24td29ya2Zsb3cpCgpSIE1hcmtkb3duIGlzIGFsc28gaW1wb3J0YW50IGJlY2F1c2UgaXQgc28gdGlnaHRseSBpbnRlZ3JhdGVzIHByb3NlIGFuZCBjb2RlLiBUaGlzIG1ha2VzIGl0IGEgZ3JlYXQgYW5hbHlzaXMgbm90ZWJvb2sgYmVjYXVzZSBpdCBsZXRzIHlvdSBkZXZlbG9wIGNvZGUgYW5kIHJlY29yZCB5b3VyIHRob3VnaHRzLiBJdDoKCiogUmVjb3JkcyB3aGF0IHlvdSBkaWQgYW5kIHdoeSB5b3UgZGlkIGl0LiBSZWdhcmRsZXNzIG9mIGhvdyBncmVhdCB5b3VyIG1lbW9yeSBpcywgaWYgeW91IGRvbuKAmXQgcmVjb3JkIHdoYXQgeW91IGRvLCB0aGVyZSB3aWxsIGNvbWUgYSB0aW1lIHdoZW4geW91IGhhdmUgZm9yZ290dGVuIGltcG9ydGFudCBkZXRhaWxzLiBXcml0ZSB0aGVtIGRvd24gc28geW91IGRvbuKAmXQgZm9yZ2V0IQoKKiBTdXBwb3J0cyByaWdvcm91cyB0aGlua2luZy4gWW91IGFyZSBtb3JlIGxpa2VseSB0byBjb21lIHVwIHdpdGggYSBzdHJvbmcgYW5hbHlzaXMgaWYgeW91IHJlY29yZCB5b3VyIHRob3VnaHRzIGFzIHlvdSBnbywgYW5kIGNvbnRpbnVlIHRvIHJlZmxlY3Qgb24gdGhlbS4gVGhpcyBhbHNvIHNhdmVzIHlvdSB0aW1lIHdoZW4geW91IGV2ZW50dWFsbHkgd3JpdGUgdXAgeW91ciBhbmFseXNpcyB0byBzaGFyZSB3aXRoIG90aGVycy4KCiogSGVscHMgb3RoZXJzIHVuZGVyc3RhbmQgeW91ciB3b3JrLiBJdCBpcyByYXJlIHRvIGRvIGRhdGEgYW5hbHlzaXMgYnkgeW91cnNlbGYsIGFuZCB5b3XigJlsbCBvZnRlbiBiZSB3b3JraW5nIGFzIHBhcnQgb2YgYSB0ZWFtLiBBIGxhYiBub3RlYm9vayBoZWxwcyB5b3Ugc2hhcmUgd2h5IHlvdSBkaWQgaXQgd2l0aCB5b3VyIGNvbGxlYWd1ZXMgb3IgbGFiIG1hdGVzLgoKLS0tCgojIyMjIFJlY29yZHMgb2YgRURBIGFuZCBDb21tdW5pY2F0aW9uCgoxLiBNZW1vIG9uIGEgc2NyYXRjaCBwYXBlcjogUiBTY3JpcHRzCjIuIFJlY29yZCBvbiBhIG5vdGVib29rOiBSIE5vdGVib29rIChhbiBSIE1hcmtkb3duIGZvcm1hdCkKMy4gU2hvcnQgcGFwZXIgb3IgYSBkaWdpdGFsIGNvbW11bmljYXRpb246IFIgTm90ZWJvb2sKMy4gUGFwZXIgb3IgYSByZXBvcnQ6IFIgTWFya2Rvd24gKGh0bWwsIHBkZiwgTVMgV29yZCwgZXRjLikKNC4gUHJlc2VudGF0aW9uIChodG1sLCBwZGYsIE1TIFBvd2VycG9pbnQsIGV0Yy4pCjUuIFB1YmxpY2F0aW9uIG9mIGEgQm9vawogICogW0JPT0tET1dOOiBXcml0ZSBIVE1MLCBQREYsIGVQdWIsIGFuZCBLaW5kbGUgYm9va3Mgd2l0aCBSIE1hcmtkb3duXShodHRwczovL2Jvb2tkb3duLm9yZykuIEZyZWUgb25saW5lIGRvY3VtZW50IGlzIHByb3ZpZGVkIGluIFtwZGYgYXMgd2VsbF0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duL3JtYXJrZG93bi5wZGYpCiAgLSBbQXJ4aXZlIFBhZ2VdKGh0dHBzOi8vYm9va2Rvd24ub3JnL2hvbWUvYXJjaGl2ZS8pIAoKLS0tCgojIyMgTGV0J3MgR2V0IFN0YXJ0ZWQKCjEuIFN0YXJ0IFIgU3R1ZGlvIC0gX1VwZGF0ZSBSIFN0dWRpbyBpZiBvbGRfCjIuIENyZWF0ZSBhIFByb2plY3QKMy4gVG9vbCA+IEluc3RhbGwgUGFja2FnZXMgYHJtYXJrZG93bmAKICAgICogT3Igb24gQ29uc29sZTogYGluc3RhbGwucGFja2FnZXMoInJtYXJrZG93biIpYAo0LiBUb29sID4gSW5zdGFsbCBQYWNrYWdlcyBgdGlueXRleGAgKGZvciBwZGYgZ2VuZXJhdGlvbikKICAgICogQWx0ZXJuYXRpdmVseSwgYGluc3RhbGwucGFja2FnZXMoJ3Rpbnl0ZXgnKWAKICAgICogSWYgVGVYIGlzIG5vdCBpbnN0YWxsZWQ6IGB0aW55dGV4OjppbnN0YWxsX3Rpbnl0ZXgoKWAgIFwjIGluc3RhbGwgVGlueVRlWAogICAgICAtIElmIHlvdSBhcmUgbm90IHN1cmUsIHBsZWFzZSBjaGVjayBvbiBgVGVybWluYWxgIGluIHRoZSBsZWZ0IGJlbG93IHBhbmU6IAogICAgICAgICsgd2hpY2ggbGF0ZXgsIHdoaWNoIG1rdGV4bHNyCjUuIExldCdzIHRyeSEgIAogICAgYS4gRmlsZSA+IE5ldyBGaWxlID4gUiBOb3RlYm9vawogICAgYi4gU2F2ZSB3aXRoIGEgZmlsZSBuYW1lLCBzYXksIHRlc3Qtbm90ZWJvb2sKICAgIGMuIFByZXZpZXcgYnkgW1ByZXZpZXddIGJ1dHRvbgogICAgZC4gUnVuIENvZGUgQ2h1bmsgYHBsb3QoY2FycylgIGFuZCB0aGVuIFByZXZpZXcgYWdhaW4uCiAgICBlLiBLbml0IFBERiwgV29yZCAoYW5kIEhUTUwpCgotLS0KCiMjIyBUZW1wbGF0ZXMKCiMjIyMgUk5vdGVib29rX1RlbXBsYXRlCgpUZW1wbGF0ZSB0byBzdWJtaXQgeW91ciBhc3NpZ25tZW50IG9mIHRoaXMgY291cnNlOiBbYFJOb3RlYm9va19UZW1wbGF0ZS5uYi5odG1sYF0oaHR0cHM6Ly9pY3UtaHN1enVraS5naXRodWIuaW8vZGE0cjIwMjJfbm90ZS9STm90ZWJvb2tfVGVtcGxhdGUubmIuaHRtbCkKCmBgYAp0aXRsZTogIlRpdGxlIG9mIFIgTm90ZWJvb2siCmF1dGhvcjogIklEIGFuZCBZb3VyIE5hbWUiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIgCm91dHB1dDoKICBodG1sX25vdGVib29rOiBudWxsCmBgYAoKCiMjIyMjIFlBTUwKCiogQ2hhbmdlIHRoZSB0aXRsZQoqIFdyaXRlIElEIGFuZCB5b3VyIG5hbWUKKiBEYXRlIGlzIGF1dG8tZ2VuZXJhdGVkIGFuZCBpbnNlcnRlZC4gSWYgeW91IHdpc2gsIHlvdSBjYW4gcmVwbGFjZSAiYHIgU3lzLkRhdGUoKWAiIGJ5IHlvdXIgZmF2b3JpdGUgZGF0ZSBzdHlsZS4KCi0tLQoKIyMjIyMgQ29kZSBDaHVuawoKKiBXaGVuIHlvdSBleGVjdXRlIG9yIHJ1biBhIGNvZGUgd2l0aGluIHRoZSBub3RlYm9vaywgdGhlIHJlc3VsdHMgYXBwZWFyIGJlbmVhdGggdGhlIGNvZGUuCiogVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSBSdW4gYnV0dG9uLCBhIHRyaWFuZ2xlIHBvaW50aW5nIHJpZ2h0LCB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyBDdHJsK1NoaWZ0K0VudGVyIChXaW4pIG9yIENtZCtTaGlmdCtFbnRlciAoTWFjKS4KKiBBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlIEluc2VydCBDaHVuayBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgQ3RybCtPcHRpb24rSSAoV2luKSBvciBDbWQrT3B0aW9uK0kgKE1hYykuCiogV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSBQcmV2aWV3IGJ1dHRvbiBvciBwcmVzcyBDdHJsK1NoaWZ0K0sgKFdpbikgb3IgQ21kK1NoaWZ0K0sgKE1hYykgdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4KKiBUaGUgcHJldmlldyBzaG93cyB5b3UgYSByZW5kZXJlZCBIVE1MIGNvcHkgb2YgdGhlIGNvbnRlbnRzIG9mIHRoZSBlZGl0b3IuIENvbnNlcXVlbnRseSwgdW5saWtlIEtuaXQsIF9QcmV2aWV3IGRvZXMgbm90IHJ1biBhbnkgUiBjb2RlIGNodW5rcy4gSW5zdGVhZCwgdGhlIG91dHB1dCBvZiB0aGUgY2h1bmsgd2hlbiBpdCB3YXMgbGFzdCBydW4gaW4gdGhlIGVkaXRvciBpcyBkaXNwbGF5ZWRfLgoKLS0tCgojIyMjIFRlc3RpbmcgUiBNYXJrZG93biBGb3JtYXRzCgpWYXJpb3VzIE91dHB1dCBGb3JtYXRzOiBbYHRlc3Qtcm1hcmtkb3duLm5iLmh0bWxgXShodHRwczovL2ljdS1oc3V6dWtpLmdpdGh1Yi5pby9kYTRyMjAyMl9ub3RlL3Rlc3Qtcm1hcmtkb3duLm5iLmh0bWwpCgpgYGAKdGl0bGU6ICJUZXN0aW5nIFIgTWFya2Rvd24gRm9ybWF0cyIKYXV0aG9yOiAiRFMtU0wiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIHBkZl9kb2N1bWVudDogCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgd29yZF9kb2N1bWVudDogCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIHBvd2VycG9pbnRfcHJlc2VudGF0aW9uOiBkZWZhdWx0CiAgaW9zbGlkZXNfcHJlc2VudGF0aW9uOgogICAgd2lkZXNjcmVlbjogeWVzCiAgICBzbWFsbGVyOiB5ZXMKICBzbGlkeV9wcmVzZW50YXRpb246IGRlZmF1bHQKICBiZWFtZXJfcHJlc2VudGF0aW9uOiBkZWZhdWx0CmBgYAoKLS0tCgojIyMjIENvbW1lbnRzIG9uIFByZXNlbnRhdGlvbiBGb3JtYXRzIGFuZCBPcHRpb25zCgoqIEZvciBzbGlkZXMsIGEgbmV3IHNsaWRlIHN0YXJ0cyBhdCBcI1wjLCB0aGUgc2Vjb25kLWxldmVsIGhlYWRpbmcuCiogYC0tLWAgaXMgcGFnZSBicmVhayBmb3IgcHJlc2VudGF0aW9uIGZvcm1hdHMuCiogRm9yIFdvcmQgYW5kIFBvd2VycG9pbnQsIHlvdSBjYW4gYWRkIHlvdXIgdGVtcGxhdGUuIFNlZSB0aGUgZG9jdW1lbnRzIGluIFJlZmVyZW5jZXMKICAtIFVzZSBSIE1hcmtkb3duIHRvIGNyZWF0ZSBhIFdvcmQgZG9jdW1lbnQgW3NpbWlsYXIgZm9yIFBvd2VyUG9pbnRdCiAgLSBTYXZlIHRoZSByZW5kZXJlZCBXb3JkIGZpbGUgYXM6IGByZWYtZG9jLXN0eWxlLmRvY3hgCiAgLSBFZGl0IHRoZSBzdHlsZXMgb2YgdGhlIGZpbGUgYHJlZi1kb2Mtc3R5bGUuZG9jeGAKICAtIEFkZCBgcmVmLWRvYy1zdHlsZS5kb2N4YCBhcyByZWZlcmVuY2VfZG9jIGluIFlBTUwgd2l0aCBpbmRlbnRpb24gYXMgYmVsb3cKCmBgYAogIHdvcmRfZG9jdW1lbnQ6IAogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHJlZmVyZW5jZV9kb2M6IHJlZi1kb2Mtc3R5bGUuZG9jeAogIHBvd2VycG9pbnRfcHJlc2VudGF0aW9uOiAKICAgIHJlZmVyZW5jZV9kb2M6IHJlZi1wcHQtc3R5bGUucHB0eApgYGAKCiogWW91IGNhbiB1c2UgYE91dHB1dCBPcHRpb25zYCBhdCB0aGUgYm90dG9tIG9mIHRoZSBnZWFyIGljb24gbmV4dCB0byBQcmV2aWV3L2tuaXQgYnV0dG9uLgoKLS0tCgojIyMgTWFya2Rvd24gTGFuZ3VhZ2UgLS0gb3IgdXNlIFdZU0lXWUcgZWRpdG9yCgoqIEhlYWRlcnM6IFwjLCBcI1wjLCBcI1wjXCMsIFwjXCNcI1wjCiogTGlzdHM6IDEuIDIuIFxsZG90cywgKiAKKiBMaW5rczogW2xpbmtlZCBwaHJhc2VdKGh0dHA6Ly9leGFtcGxlLmNvbSkKKiBJbWFnZXM6IGAhW2FsdCB0ZXh0XShmaWd1cmVzL2ZpbGVuYW1lLmpwZylgCiogQmxvY2sgcXVvdGVzIiA+IChibG9jaykgCiogXExhVGVYXCAgZXF1YXRpb25zOiBlLmcuIGAkXGZyYWN7YX17Yn0kYCBmb3IgJFxmcmFje2F9e2J9JAoqIEhvcml6b250YWwgcnVsZXM6IFRocmVlIG9yIG1vcmUgYXN0ZXJpc2tzIG9yIGRhc2hlcyAoKioqIG9yICAtIC0gLSApCiogVGFibGVzCiogRm9vdG5vdGVzCiogQmlibGlvZ3JhcGhpZXMgYW5kIENpdGF0aW9ucwoqIFNsaWRlIGJyZWFrcwoqIF9JdGFsaWNpemVkIHRleHRfIGJ5IGBfaXRhbGljX2AsICoqQm9sZCB0ZXh0KiogYnkgYCoqYm9sZCoqYAoqIFN1cGVyc2NyaXB0cywgU3Vic2NyaXB0cywgU3RyaWtldGhyb3VnaCB0ZXh0CgotLS0KCiMjIyMgVmlzdWFsIFIgTWFya2Rvd24KCj5SIFN0dWRpbyBpbnRyb2R1Y2VkIFZpc3VhbCBFZGl0b3IgdG93YXJkcyB0aGUgZW5kIG9mIDIwMjEuIEl0IHNlZW1zIHRvIGJlIHN0YWJsZSBidXQgaXQgaXMgbm90IHBlcmZlY3QgdG8gZ28gYmFjayBhbmQgZm9ydGggZnJvbSB0aGUgb3JpZ2luYWwgZWRpdG9yIHVzaW5nIHRhZ3MuIEkgYWx3YXlzIHVzZSB0aGUgb3JpZ2luYWwgZWRpdG9yIGFuZCBJIGFtIGNvbmZpZGVudCBvbiBhbGwgdGhlIGZ1bmN0aW9ucyBvZiBpdCBidXQgSSBkbyBub3QgaGF2ZSBtdWNoIGV4cGVyaWVuY2Ugb24gVmlzdWFsIEVkaXRvci4gW015IE5vdGUgaW4gUUFMTDQwMSAyMDIxXQogIAogICogaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby92aXN1YWwtbWFya2Rvd24tZWRpdGluZy8KCi0tLQoKIyMjIFJlZmVyZW5jZXMKCiogUG9zaXQgUHJpbWVyczogW1JlcG9ydCBSZXByb2R1Y2libHldKGh0dHBzOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2xlc3Nvbi0xLmh0bWw/X2dhPTIuNjA3MDg1OTEuMzE3NjIxMjc3LjE2NzExNDI2MTQtMjAwNDQ3Mjc0Mi4xNjcxMTQyNjE0KQoqIE1hcmtkb3duIFF1aWNrIFJlZmVyZW5jZTogVG9wIE1lbnUgQmFyIFw+IEhlbHAgXD4gTWFya2Rvd24gUXVpY2sgUmVmZXJlbmNlCiogQ2hlYXQgU2hlZXQgKFRvcCBNZW51IEJhcjogSGVscCBcPiBDaGVhdCBTaGVldHMpOiBSTWFya2Rvd24gQ2hlYXQgU2hlZXQsIFJNYXJrZG93biBSZWZlcmVuY2UgR3VpZGUKKiBCb29rczoKICAtIEluIFRleHRib29rOiBbUiBmb3IgRGF0YSBTY2llbmNlOiBDb21tdW5pY2F0ZV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9jb21tdW5pY2F0ZS1pbnRyby5odG1sI2NvbW11bmljYXRlLWludHJvKQogIC0gW1IgTWFya2Rvd246IFRoZSBEZWZpbml0aXZlIEd1aWRlXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vKSBieSBZaWh1aSBYaWUsIEouIEouIEFsbGFpcmUsIEdhcnJldHQgR3JvbGVtdW5kCiAgLSBbUiBNYXJrZG93biBDb29rYm9va10oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLWNvb2tib29rLykgYnkgWWlodWkgWGllLCBDaHJpc3RvcGhlIERlcnZpZXV4LCBFbWlseSBSaWVkZXJlcgoqIE1hcmtkb3duOiBSIE1hcmtkb3duIGlzIGJhc2VkIG9uIHRoZSBNYXJrZG93biBsYW5ndWFnZSBvZiBQYW5kb2MKICAtIFtQYW5kb2MncyBNYXJrZG93bl0oaHR0cHM6Ly9wYW5kb2Mub3JnL01BTlVBTC5odG1sI3BhbmRvY3MtbWFya2Rvd24pOiBEZXRhaWxlZCBJbmZvcm1hdGlvbgogIC0gW01hcmtkb3duIFR1dG9yaWFsc10oaHR0cHM6Ly93d3cubWFya2Rvd250dXRvcmlhbC5jb20pOiBJbnRlcmFjdGl2ZSBQcmFjdGljdW0KICAtIFtEQVJJTkcgRklSRUJBTEw6IE1hcmtkb3duXShodHRwczovL2RhcmluZ2ZpcmViYWxsLm5ldC9wcm9qZWN0cy9tYXJrZG93bi8pIChkZXRhaWxlZCBleHBsYW5hdGlvbiBhbmQgZWRpdG9yIGFzIERpbmd1cykKKiBQb3N0IGVycm9yIG1lc3NhZ2VzIHRvIGEgd2ViIHNlYXJjaCBlbmdpbmUuCgoKCiMjIERhdGEgVHJhbnNmb3JhbXRpb24gd2l0aCBgZHBseXJgCgojIyMgYGRwbHlyYCBbT3ZlcnZpZXddKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZykKCmRwbHlyIGlzIGEgZ3JhbW1hciBvZiBkYXRhIG1hbmlwdWxhdGlvbiwgcHJvdmlkaW5nIGEgY29uc2lzdGVudCBzZXQgb2YgdmVyYnMgdGhhdCBoZWxwIHlvdSBzb2x2ZSB0aGUgbW9zdCBjb21tb24gZGF0YSBtYW5pcHVsYXRpb24gY2hhbGxlbmdlczoKCiogYHNlbGVjdCgpYCBwaWNrcyB2YXJpYWJsZXMgYmFzZWQgb24gdGhlaXIgbmFtZXMuCiogYGZpbHRlcigpYCBwaWNrcyBjYXNlcyBiYXNlZCBvbiB0aGVpciB2YWx1ZXMuCiogYG11dGF0ZSgpYCBhZGRzIG5ldyB2YXJpYWJsZXMgdGhhdCBhcmUgZnVuY3Rpb25zIG9mIGV4aXN0aW5nIHZhcmlhYmxlcwoqIGBzdW1tYXJpc2UoKWAgcmVkdWNlcyBtdWx0aXBsZSB2YWx1ZXMgZG93biB0byBhIHNpbmdsZSBzdW1tYXJ5LgoqIGBhcnJhbmdlKClgIGNoYW5nZXMgdGhlIG9yZGVyaW5nIG9mIHRoZSByb3dzLgoqIGBncm91cF9ieSgpYCB0YWtlcyBhbiBleGlzdGluZyB0YmwgYW5kIGNvbnZlcnRzIGl0IGludG8gYSBncm91cGVkIHRibC4KCllvdSBjYW4gbGVhcm4gbW9yZSBhYm91dCB0aGVtIGluIHZpZ25ldHRlKCJkcGx5ciIpLiBBcyB3ZWxsIGFzIHRoZXNlIHNpbmdsZS10YWJsZSB2ZXJicywgZHBseXIgYWxzbyBwcm92aWRlcyBhIHZhcmlldHkgb2YgdHdvLXRhYmxlIHZlcmJzLCB3aGljaCB5b3UgY2FuIGxlYXJuIGFib3V0IGluIHZpZ25ldHRlKCJ0d28tdGFibGUiKS4KCklmIHlvdSBhcmUgbmV3IHRvIGRwbHlyLCB0aGUgYmVzdCBwbGFjZSB0byBzdGFydCBpcyBbdGhlIGRhdGEgdHJhbnNmb3JtYXRpb24gY2hhcHRlciBpbiBSIGZvciBkYXRhIHNjaWVuY2VdKGh0dHA6Ly9yNGRzLmhhZC5jby5uei90cmFuc2Zvcm0uaHRtbCkuCgotLS0KCiMjIyBbYHNlbGVjdGBdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2Uvc2VsZWN0Lmh0bWwpOiBTdWJzZXQgY29sdW1ucyB1c2luZyB0aGVpciBuYW1lcyBhbmQgdHlwZXMKCkhlbHBlciBGdW5jdGlvbgl8IFVzZQl8IEV4YW1wbGUKLS0tfC0tLS0tLS18LS0tLS0tLS0KLQl8IENvbHVtbnMgZXhjZXB0CXwgc2VsZWN0KGJhYnluYW1lcywgLXByb3ApCjoJfCBDb2x1bW5zIGJldHdlZW4gKGluY2x1c2l2ZSkJfCBzZWxlY3QoYmFieW5hbWVzLCB5ZWFyOm4pCmNvbnRhaW5zKCkgfAlDb2x1bW5zIHRoYXQgY29udGFpbnMgYSBzdHJpbmcgfAlzZWxlY3QoYmFieW5hbWVzLCBjb250YWlucygibiIpKQplbmRzX3dpdGgoKQl8IENvbHVtbnMgdGhhdCBlbmRzIHdpdGggYSBzdHJpbmcJfCBzZWxlY3QoYmFieW5hbWVzLCBlbmRzX3dpdGgoIm4iKSkKbWF0Y2hlcygpCXwgQ29sdW1ucyB0aGF0IG1hdGNoZXMgYSByZWdleCB8CXNlbGVjdChiYWJ5bmFtZXMsIG1hdGNoZXMoIm4iKSkKbnVtX3JhbmdlKCkJfCBDb2x1bW5zIHdpdGggYSBudW1lcmljYWwgc3VmZml4IGluIHRoZSByYW5nZSB8IE5vdCBhcHBsaWNhYmxlIHdpdGggYmFieW5hbWVzCm9uZV9vZigpIHwJQ29sdW1ucyB3aG9zZSBuYW1lIGFwcGVhciBpbiB0aGUgZ2l2ZW4gc2V0IHwJc2VsZWN0KGJhYnluYW1lcywgb25lX29mKGMoInNleCIsICJnZW5kZXIiKSkpCnN0YXJ0c193aXRoKCkJfCBDb2x1bW5zIHRoYXQgc3RhcnRzIHdpdGggYSBzdHJpbmcJfCBzZWxlY3QoYmFieW5hbWVzLCBzdGFydHNfd2l0aCgibiIpKQoKLS0tCgojIyMgW2BmaWx0ZXJgXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2ZpbHRlci5odG1sKTogU3Vic2V0IHJvd3MgdXNpbmcgY29sdW1uIHZhbHVlcwoKTG9naWNhbCBvcGVyYXRvcgl8IHRlc3RzCXwgRXhhbXBsZQotLXwtLS0tLXwtLS0KPgl8IElzIHggZ3JlYXRlciB0aGFuIHk/IHwJeCA+IHkKPj0JfCBJcyB4IGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB5PyB8CXggPj0geQo8CXwgSXMgeCBsZXNzIHRoYW4geT8JfCB4IDwgeQo8PQl8IElzIHggbGVzcyB0aGFuIG9yIGVxdWFsIHRvIHk/IHwgCXggPD0geQo9PQl8IElzIHggZXF1YWwgdG8geT8gfAl4ID09IHkKIT0JfCBJcyB4IG5vdCBlcXVhbCB0byB5PyB8CXggIT0geQppcy5uYSgpCXwgSXMgeCBhbiBOQT8JfCBpcy5uYSh4KQohaXMubmEoKSB8CUlzIHggbm90IGFuIE5BPyB8CSFpcy5uYSh4KQoKLS0tCgojIyMgW2BhcnJhbmdlYF0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9hcnJhbmdlLmh0bWwpIGFuZCBgUGlwZSAlPiVgCgoqIGBhcnJhbmdlKClgIG9yZGVycyB0aGUgcm93cyBvZiBhIGRhdGEgZnJhbWUgYnkgdGhlIHZhbHVlcyBvZiBzZWxlY3RlZCBjb2x1bW5zLgoKVW5saWtlIG90aGVyIGBkcGx5cmAgdmVyYnMsIGBhcnJhbmdlKClgIGxhcmdlbHkgaWdub3JlcyBncm91cGluZzsgeW91IG5lZWQgdG8gZXhwbGljaXRseSBtZW50aW9uIGdyb3VwaW5nIHZhcmlhYmxlcyAoYG9yIHVzZSAuYnlfZ3JvdXAgPSBUUlVFKSBpbiBvcmRlciB0byBncm91cCBieSB0aGVtLCBhbmQgZnVuY3Rpb25zIG9mIHZhcmlhYmxlcyBhcmUgZXZhbHVhdGVkIG9uY2UgcGVyIGRhdGEgZnJhbWUsIG5vdCBvbmNlIHBlciBncm91cC4KCiogW2BwaXBlc2BdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovcGlwZXMuaHRtbCkgaW4gUiBmb3IgRGF0YSBTY2llbmNlLgoKLS0tCgojIyMgW2BtdXRhdGVgXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL211dGF0ZS5odG1sKSAKCiogQ3JlYXRlLCBtb2RpZnksIGFuZCBkZWxldGUgY29sdW1ucwoKKiBVc2VmdWwgbXV0YXRlIGZ1bmN0aW9ucwoKICAtICssIC0sIGxvZygpLCBldGMuLCBmb3IgdGhlaXIgdXN1YWwgbWF0aGVtYXRpY2FsIG1lYW5pbmdzCgogIC0gbGVhZCgpLCBsYWcoKQoKICAtIGRlbnNlX3JhbmsoKSwgbWluX3JhbmsoKSwgcGVyY2VudF9yYW5rKCksIHJvd19udW1iZXIoKSwgY3VtZV9kaXN0KCksIG50aWxlKCkKCiAgLSBjdW1zdW0oKSwgY3VtbWVhbigpLCBjdW1taW4oKSwgY3VtbWF4KCksIGN1bWFueSgpLCBjdW1hbGwoKQoKICAtIG5hX2lmKCksIGNvYWxlc2NlKCkjIyMgYGdyb3VwX2J5KClgIGFuZCBgc3VtbWFyaXNlKClgCgotLS0KCiMjIyBbYGdyb3VwX2J5YF0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9ncm91cF9ieS5odG1sKQoKLS0tCgojIyMgW2BzdW1tYXJpc2VgIG9yIGBzdW1tYXJpemVgXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3N1bW1hcmlzZS5odG1sKQoKIyMjIyBTdW1tYXJ5IGZ1bmN0aW9ucwoKU28gZmFyIG91ciBzdW1tYXJpc2UoKSBleGFtcGxlcyBoYXZlIHJlbGllZCBvbiBzdW0oKSwgbWF4KCksIGFuZCBtZWFuKCkuIEJ1dCB5b3UgY2FuIHVzZSBhbnkgZnVuY3Rpb24gaW4gc3VtbWFyaXNlKCkgc28gbG9uZyBhcyBpdCBtZWV0cyBvbmUgY3JpdGVyaWE6IHRoZSBmdW5jdGlvbiBtdXN0IHRha2UgYSB2ZWN0b3Igb2YgdmFsdWVzIGFzIGlucHV0IGFuZCByZXR1cm4gYSBzaW5nbGUgdmFsdWUgYXMgb3V0cHV0LiBGdW5jdGlvbnMgdGhhdCBkbyB0aGlzIGFyZSBrbm93biBhcyBzdW1tYXJ5IGZ1bmN0aW9ucyBhbmQgdGhleSBhcmUgY29tbW9uIGluIHRoZSBmaWVsZCBvZiBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzLiBTb21lIG9mIHRoZSBtb3N0IHVzZWZ1bCBzdW1tYXJ5IGZ1bmN0aW9ucyBpbmNsdWRlOgoKMS4gTWVhc3VyZXMgb2YgbG9jYXRpb24gLSBtZWFuKHgpLCBtZWRpYW4oeCksIHF1YW50aWxlKHgsIDAuMjUpLCBtaW4oeCksIGFuZCBtYXgoeCkKMi4gTWVhc3VyZXMgb2Ygc3ByZWFkIC0gc2QoeCksIHZhcih4KSwgSVFSKHgpLCBhbmQgbWFkKHgpCjMuIE1lYXN1cmVzIG9mIHBvc2l0aW9uIC0gZmlyc3QoeCksIG50aCh4LCAyKSwgYW5kIGxhc3QoeCkKNC4gQ291bnRzIC0gbl9kaXN0aW5jdCh4KSBhbmQgbigpLCB3aGljaCB0YWtlcyBubyBhcmd1bWVudHMsIGFuZCByZXR1cm5zIHRoZSBzaXplIG9mIHRoZSBjdXJyZW50IGdyb3VwIG9yIGRhdGEgZnJhbWUuCjUuIENvdW50cyBhbmQgcHJvcG9ydGlvbnMgb2YgbG9naWNhbCB2YWx1ZXMgLSBzdW0oIWlzLm5hKHgpKSwgd2hpY2ggY291bnRzIHRoZSBudW1iZXIgb2YgVFJVRXMgcmV0dXJuZWQgYnkgYSBsb2dpY2FsIHRlc3Q7IG1lYW4oeSA9PSAwKSwgd2hpY2ggcmV0dXJucyB0aGUgcHJvcG9ydGlvbiBvZiBUUlVFcyByZXR1cm5lZCBieSBhIGxvZ2ljYWwgdGVzdC4KCgogIC0gaWZfZWxzZSgpLCByZWNvZGUoKSwgY2FzZV93aGVuKCkKCi0tLQoKIyMjIExlYXJuIGBkcGx5cmAgYnkgRXhhbXBsZXMKCiMjIyMgRGF0YSBgaXJpc2AKCmBgYHtyfQppcmlzCmBgYAoKCi0tLQoKYGBge3J9CnN1bW1hcnkoaXJpcykKYGBgCgotLS0KCiMjIyMgYHNlbGVjdGAgMSAtIGNvbHVtbnMgMSwgMiwgNQoKYGBge3J9CnNlbGVjdChpcmlzLCBjKDEsMiw1KSkKYGBgCgotLS0KCiMjIyMgYHNlbGVjdGAgMiAtIGV4Y2VwdCBTcGVjaWVzCgpgYGB7cn0Kc2VsZWN0KGlyaXMsIC1TcGVjaWVzKQpgYGAKCi0tLQoKIyMjIyBgc2VsZWN0YCAzIC0gY2hhbmdlIGNvbHVtbiBuYW1lcwoKYGBge3J9CnNlbGVjdChpcmlzLCBzbCA9IFNlcGFsLkxlbmd0aCwgc3cgPSBTZXBhbC5XaWR0aCwgc3AgPSBTcGVjaWVzKQpgYGAKCi0tLQoKIyMjIyBgZmlsdGVyYCAtIGJ5IG5hbWVzCgpgYGB7cn0KZmlsdGVyKGlyaXMsIFNwZWNpZXMgPT0gInZpcmdpbmljYSIpCmBgYAoKCi0tLQoKIyMjIyBgYXJyYW5nZWAgIC0gYXNjZW5kaW5nIGFuZCBkZXNjZW5kaW5nIG9yZGVyCgpgYGB7cn0KYXJyYW5nZShpcmlzLCBTZXBhbC5MZW5ndGgsIGRlc2MoU2VwYWwuV2lkdGgpKQpgYGAKCi0tLQoKIyMjIyBgbXV0YXRlYCAtIHJhbmsKCmBgYHtyfQppcmlzICU+JSBtdXRhdGUoc2xfcmFuayA9IG1pbl9yYW5rKFNlcGFsLkxlbmd0aCkpICU+JSBhcnJhbmdlKHNsX3JhbmspCmBgYAoKLS0tCgojIyMjIGBncm91cF9ieWAgYW5kIGBzdW1tYXJpemVgCgpgYGB7cn0KaXJpcyAlPiUgCiAgZ3JvdXBfYnkoU3BlY2llcykgJT4lIAogIHN1bW1hcml6ZShzbCA9IG1lYW4oU2VwYWwuTGVuZ3RoKSwgc3cgPSBtZWFuKFNlcGFsLldpZHRoKSwgCiAgcGwgPSBtZWFuKFBldGFsLkxlbmd0aCksIHB3ID0gbWVhbihQZXRhbC5XaWR0aCkpCmBgYAoKKiBtZWFuOiBgbWVhbigpYCBvciBgbWVhbih4LCBuYS5ybSA9IFRSVUUpYCAtIGFyaXRobWV0aWMgbWVhbiAoYXZlcmFnZSkKKiBtZWRpYW46IGBtZWRpYW4oKWAgb3IgYG1lZGlhbih4LCBuYS5ybSA9IFRSVUUpYCAtIG1pZCB2YWx1ZQoKLS0tCgpGb3IgbW9yZSBleGFtcGxlcyBzZWUgCgpbZHBscl9pcmlzXShodHRwczovL2ljdS1oc3V6dWtpLmdpdGh1Yi5pby9kYTRyMjAyMl9ub3RlL2RwbHlyLWlyaXMubmIuaHRtbCkKCgojIyMgUmVmZXJlbmNlcyBvZiBgZHBseXJgCgoqIFRleHRib29rOiBbUiBmb3IgRGF0YSBTY2llbmNlLCBQYXJ0IElJIEV4cGxvcmVdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovd3JhbmdsZS1pbnRyby5odG1sI3dyYW5nbGUtaW50cm8pCgo6Ojogey5ibG9ja30KIyMjIyBSU3R1ZGlvIFByaW1lcnM6IFNlZSBSZWZlcmVuY2VzIGluIE1vb2RsZSBhdCB0aGUgYm90dG9tCgoxLiBUaGUgQmFzaWNzIC0tIFtyNGRzOiBFeHBsb3JlLCBJXShodHRwczovL3I0ZHMuaGFkLmNvLm56L2V4cGxvcmUtaW50cm8uaHRtbCNleHBsb3JlLWludHJvKQogIC0gW1Zpc3VhbGl6YXRpb24gQmFzaWNzXShodHRwczovL3JzdHVkaW8uY2xvdWQvbGVhcm4vcHJpbWVycy8xLjEpCiAgLSBbUHJvZ3JhbW1pbmcgQmFzaWNzXShodHRwczovL3JzdHVkaW8uY2xvdWQvbGVhcm4vcHJpbWVycy8xLjIpCjIuICoqV29yayB3aXRoIERhdGEqKiAtLSBbcjRkczogV3JhbmdsZSwgSV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei93cmFuZ2xlLWludHJvLmh0bWwjd3JhbmdsZS1pbnRybykKICAtICoqV29ya2luZyB3aXRoIFRpYmJsZXMqKgogIC0gKipJc29sYXRpbmcgRGF0YSB3aXRoIGRwbHlyKioKICAtICoqRGVyaXZpbmcgSW5mb3JtYXRpb24gd2l0aCBkcGx5cioqCjMuIFZpc3VhbGl6ZSBEYXRhIC0tIFtyNGRzOiBFeHBsb3JlLCBJSV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9leHBsb3JlLWludHJvLmh0bWwjZXhwbG9yZS1pbnRybykKNC4gVGlkeSBZb3VyIERhdGEgLS0gW3I0ZHM6IFdyYW5nbGUsIElJXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3dyYW5nbGUtaW50cm8uaHRtbCN3cmFuZ2xlLWludHJvKQo1LiBJdGVyYXRlIC0tIFtyNGRzOiBQcm9ncmFtXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3Byb2dyYW0taW50cm8uaHRtbCNwcm9ncmFtLWludHJvKQo2LiBXcml0ZSBGdW5jdGlvbnMgLS0gW3I0ZHM6IFByb2dyYW1dKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovcHJvZ3JhbS1pbnRyby5odG1sI3Byb2dyYW0taW50cm8pCjo6OiAKCi0tLQoKIyMjIExlYXJuIGBkcGx5cmAgYnkgRXhhbXBsZXMgSUkgLSBgZ2FwbWluZGVyYAoKCgojIyMjIGBnZ3Bsb3QyYCBbT3ZlcnZpZXddKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnKQoKYGdncGxvdDJgIGlzIGEgc3lzdGVtIGZvciBkZWNsYXJhdGl2ZWx5IGNyZWF0aW5nIGdyYXBoaWNzLCBiYXNlZCBvbiBbVGhlIEdyYW1tYXIgb2YgR3JhcGhpY3NdKGh0dHBzOi8vYW16bi50by8yZWYxZVdwKS4gWW91IHByb3ZpZGUgdGhlIGRhdGEsIHRlbGwgZ2dwbG90MiBob3cgdG8gbWFwIHZhcmlhYmxlcyB0byBhZXN0aGV0aWNzLCB3aGF0IGdyYXBoaWNhbCBwcmltaXRpdmVzIHRvIHVzZSwgYW5kIGl0IHRha2VzIGNhcmUgb2YgdGhlIGRldGFpbHMuCgoqKkV4YW1wbGVzKioKYGBgCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKQpgYGAKYGBgCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKHggPSBjbGFzcywgeSA9IGh3eSkpCmBgYAoKKipUZW1wbGF0ZSoqCmBgYApnZ3Bsb3QoZGF0YSA9IDxEQVRBPikgKyAKICA8R0VPTV9GVU5DVElPTj4obWFwcGluZyA9IGFlcyg8TUFQUElOR1M+KSkKYGBgCgotLS0KCiMjIyMgR2FwbWluZGVyIGFuZCBSIFBhY2thZ2UgYGdhcG1pbmRlcmAKCj4gR2FwbWluZGVyIHdhcyBmb3VuZGVkIGJ5IE9sYSBSb3NsaW5nLCBBbm5hIFJvc2xpbmcgUsO2bm5sdW5kLCBhbmQgSGFucyBSb3NsaW5nCgotICAgR2FwbWluZGVyOiA8aHR0cHM6Ly93d3cuZ2FwbWluZGVyLm9yZz4KCiAgICAtICAgVGVzdCBvbiBUb3A6IFlvdSBhcmUgcHJvYmFibHkgd3JvbmcgYWJvdXQgLSB1cGdyYWRlIHlvdXIgd29ybGR2aWV3CiAgICAtICAgQnViYmxlIENoYXJ0OiA8aHR0cHM6Ly93d3cuZ2FwbWluZGVyLm9yZy90b29scy8jJGNoYXJ0LXR5cGU9YnViYmxlcyZ1cmw9djE+CiAgICAtICAgRGFsbGFyIFN0cmVldDogPGh0dHBzOi8vd3d3LmdhcG1pbmRlci5vcmcvdG9vbHMvIyRjaGFydC10eXBlPWJ1YmJsZXMmdXJsPXYxPgogICAgLSAgIERhdGE6IDxodHRwczovL3d3dy5nYXBtaW5kZXIub3JnL2RhdGEvPgoKLSAgIFIgUGFja2FnZSBnYXBtaW5kZXIgYnkgSmVubmlmZXIgQnJ5YW4KCiAgICAtICAgUGFja2FnZSBzaXRlOiA8aHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1nYXBtaW5kZXI+CiAgICAtICAgU2l0ZTogPGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2dhcG1pbmRlcj4KICAgIC0gICBEb2N1bWVudHM6IDxodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvZ2FwbWluZGVyL3ZlcnNpb25zLzAuMy4wPgoKLSAgIFBhY2thZ2UgSGVscCBgP2dhcG1pbmRlcmAgb3IgYGdhcG1pbmRlcmAgaW4gdGhlIHNlYXJjaCB3aW5kb3cgb2YgSGVscAoKICAgIC0gICBUaGUgbWFpbiBkYXRhIGZyYW1lIGdhcG1pbmRlciBoYXMgMTcwNCByb3dzIGFuZCA2IHZhcmlhYmxlczoKICAgICAgICAtICAgY291bnRyeTogZmFjdG9yIHdpdGggMTQyIGxldmVscwogICAgICAgIC0gICBjb250aW5lbnQ6IGZhY3RvciB3aXRoIDUgbGV2ZWxzCiAgICAgICAgLSAgIHllYXI6IHJhbmdlcyBmcm9tIDE5NTIgdG8gMjAwNyBpbiBpbmNyZW1lbnRzIG9mIDUgeWVhcnMKICAgICAgICAtICAgbGlmZUV4cDogbGlmZSBleHBlY3RhbmN5IGF0IGJpcnRoLCBpbiB5ZWFycwogICAgICAgIC0gICBwb3A6IHBvcHVsYXRpb24KICAgICAgICAtICAgZ2RwUGVyY2FwOiBHRFAgcGVyIGNhcGl0YSAoVVNcJCwgaW5mbGF0aW9uLWFkanVzdGVkKQoKLS0tCgpgYGB7ciBwYWNrYWdlcywgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2FwbWluZGVyKQpsaWJyYXJ5KFdESSkKYGBgCgotLS0KCiMjIyMgUiBQYWNrYWdlIGBnYXBtaW5kZXJgIGRhdGEKCmBgYHtyfQpkZiA8LSBnYXBtaW5kZXIKZGYKYGBgCgotLS0KCmBgYHtyfQpnbGltcHNlKGRmKQpgYGAKCi0tLQoKYGBge3J9CnN1bW1hcnkoZGYpCmBgYAoKLS0tCgojIyMjIFRpZHl2ZXJzZTo6Z2dwbG90CgojIyMjIyBGaXJzdCBUcnkgLSB3aXRoIGZhaWx1cmVzCgpgYGB7cn0KZ2dwbG90KGRmLCBhZXMoeCA9IHllYXIsIHkgPSBsaWZlRXhwKSkgKyBnZW9tX3BvaW50KCkKYGBgCgotLS0KCmBgYHtyfQpnZ3Bsb3QoZGYsIGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHApKSArIGdlb21fbGluZSgpCmBgYAoKLS0tCgpgYGB7cn0KZ2dwbG90KGRmLCBhZXMoeCA9IHllYXIsIHkgPSBsaWZlRXhwKSkgKyBnZW9tX2JveHBsb3QoKQpgYGAKCi0tLQoKYGBge3J9CnR5cGVvZihwdWxsKGRmLCB5ZWFyKSkgIyBzYW1lIGFzIHR5cGVvZihkZiR5ZWFyKQpgYGAKCi0tLQoKYGBge3J9CmdncGxvdChkZiwgYWVzKHkgPSBsaWZlRXhwLCBncm91cCA9IHllYXIpKSArIGdlb21fYm94cGxvdCgpCmBgYAoKLS0tCgojIyMjIyBCb3ggUGxvdAoKYGBge3J9CmdncGxvdChkZiwgYWVzKHggPSBhc19mYWN0b3IoeWVhciksIHkgPSBsaWZlRXhwKSkgKyBnZW9tX2JveHBsb3QoKQpgYGAKCi0tLQoKIyMjIyBBcHBsaWNhdGlvbnMgb2YgYGRwbHlyYAoKIyMjIyMgYGZpbHRlcmAKCmBgYHtyfQpkZiAlPiUgZmlsdGVyKGNvdW50cnkgPT0gIkFmZ2hhbmlzdGFuIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHApKSArIGdlb21fbGluZSgpCmBgYAoKLS0tCgpgYGB7cn0KZGYgJT4lIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiQWZnaGFuaXN0YW4iLCAiSmFwYW4iKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHAsIGNvbG9yID0gY291bnRyeSkpICsgZ2VvbV9saW5lKCkKYGBgCgotLS0KCmBgYHtyfQpkZiAlPiUgZGlzdGluY3QoY291bnRyeSkgJT4lIHB1bGwoKQpgYGAKCi0tLQoKYGBge3J9CmRmICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkJyYXppbCIsICJSdXNzaWEiLCAiSW5kaWEiLCAiQ2hpbmEiKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHAsIGNvbG9yID0gY291bnRyeSkpICsgZ2VvbV9saW5lKCkKYGBgCgpSdXNzaWFuIGRhdGEgaXMgbWlzc2luZy4KCi0tLQoKIyMjIEV4ZXJjaXNlcwoKMS4gIENoYW5nZSBgbGlmZUV4cGAgdG8gYHBvcGAgYW5kIGBnZHBQZXJjYXBgIGFuZCBkbyB0aGUgc2FtZS4KMi4gIENob29zZSBBU0VBTiBjb3VudHJpZXMgYW5kIGRvIHRoZSBzaW1pbGFyIGludmVzdGlnYXRpb25zLgoKLSAgIEJydW5laSwgQ2FtYm9kaWEsIEluZG9uZXNpYSwgTGFvcywgTWFsYXlzaWEsIE15YW5tYXIsIFBoaWxpcHBpbmVzLCBTaW5nYXBvcmUuCgozLiAgQ2hvb3NlIHNldmVyYWwgY291bnRyaWVzIGJ5IHlvdXJzZWxmIGFuZCBkbyB0aGUgc2ltaWxhciBpbnZlc3RpZ2F0aW9ucy4KCi0tLQoKIyMjIGBncm91cF9ieWAgYW5kIGBzdW1tYXJpemVgCgpMZXQgdXMgdXNlIHRoZSB2YXJpYWJsZSBgY29udGluZW50YCBhbmQgc3VtbWFyaXplIHRoZSBkYXRhLgoKYGBge3J9CmRmX2xpZmVFeHAgPC0gZGYgJT4lIGdyb3VwX2J5KGNvbnRpbmVudCwgeWVhcikgJT4lIAogIHN1bW1hcml6ZShtZWFuX2xpZmVFeHAgPSBtZWFuKGxpZmVFeHApLCBtZWRpYW5fbGlmZUV4cCA9IG1lZGlhbihsaWZlRXhwKSwgbWF4X2xpZmVFeHAgPSBtYXgobGlmZUV4cCksIG1pbl9saWZlRXhwID0gbWluKGxpZmVFeHApLCAuZ3JvdXBzID0gImtlZXAiKQpgYGAKCi0tLQoKYGBge3J9CmRmX2xpZmVFeHAKYGBgCgotLS0KCmBgYHtyfQpkZiAlPiUgZmlsdGVyKHllYXIgJWluJSBjKDE5NTIsIDE5ODcsIDIwMDcpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9YXNfZmFjdG9yKHllYXIpLCB5ID0gbGlmZUV4cCwgZmlsbCA9IGNvbnRpbmVudCkpICsKICBnZW9tX2JveHBsb3QoKQpgYGAKCi0tLQoKYGBge3J9CmRmX2xpZmVFeHAgJT4lIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBtZWFuX2xpZmVFeHAsIGNvbG9yID0gY29udGluZW50KSkgKwogIGdlb21fbGluZSgpCmBgYAoKLS0tCgpgYGB7cn0KZGZfbGlmZUV4cCAlPiUgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IG1lYW5fbGlmZUV4cCwgY29sb3IgPSBjb250aW5lbnQsIGxpbmV0eXBlID0gY29udGluZW50KSkgKwogIGdlb21fbGluZSgpCmBgYAoKLS0tCgpgYGB7cn0KZGZfbGlmZUV4cCAlPiUgZ2dwbG90KCkgKwogIGdlb21fbGluZShhZXMoeCA9IHllYXIsIHkgPSBtZWFuX2xpZmVFeHAsIGNvbG9yID0gY29udGluZW50KSkgKyAKICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gbWVkaWFuX2xpZmVFeHAsIGxpbmV0eXBlID0gY29udGluZW50KSkKYGBgCgoKIyMgVGhlIFdlZWsgVGhyZWUgQXNzaWdubWVudCAoaW4gTW9vZGxlKQoKKipSIE1hcmtkb3duIGFuZCBgZHBseXJgKioKCiogQ3JlYXRlIGFuIFIgTm90ZWJvb2sgb2YgYSBEYXRhIEFuYWx5c2lzIGNvbnRhaW5pbmcgdGhlIGZvbGxvd2luZyBhbmQgc3VibWl0IHRoZSByZW5kZXJlZCBIVE1MIGZpbGUgKGVnLiBgYTJfMTIzNDU2Lm5iLmh0bWxgKQogIDEuIGNyZWF0ZSBhbiBSIE5vdGVib29rIHVzaW5nIHRoZSBSIE5vdGVib29rIFRlbXBsYXRlIGluIE1vb2RsZSwgIHNhdmUgYXMgYGEyXzEyMzQ1Ni5SbWRgLCAKICAyLiB3cml0ZSB5b3VyIG5hbWUgYW5kIElEIGFuZCB0aGUgY29udGVudHMsIAogIDMuIHJ1biBlYWNoIGNvZGUgYmxvY2ssIAogIDQuIHByZXZpZXcgdG8gY3JlYXRlIGBhMl8xMjM0NTYubmIuaHRtbGAsCiAgNS4gc3VibWl0ICBgYTJfMTIzNDU2Lm5iLmh0bWxgIHRvIE1vb2RsZS4KCjEuIFBpY2sgZGF0YSBmcm9tIHRoZSBidWlsdC1pbiBkYXRhc2V0cyBiZXNpZGVzIGBjYXJzYC4gKGBsaWJyYXJ5KGhlbHAgPSAiZGF0YXNldHMiKWAgb3IgZ28gdG8gdGhlIHNpdGUgW1RoZSBSIERhdGFzZXRzIFBhY2thZ2VdKGh0dHBzOi8vc3RhdC5ldGh6LmNoL1ItbWFudWFsL1ItZGV2ZWwvbGlicmFyeS9kYXRhc2V0cy9odG1sLzAwSW5kZXguaHRtbCkpCgogICAgLSBJbmZvcm1hdGlvbiBvZiB0aGUgZGF0YTogTmFtZSwgRGVzY3JpcHRpb24sIFVzYWdlLCBGb3JtYXQsIFNvdXJjZSwgUmVmZXJlbmNlcyAoSGludDogP2NhcnMpCiAgICAtIFVzZSBgaGVhZCgpYCwgYHN0cigpYCwgLi4uLCBhbmQgY3JlYXRlIGF0IGxlYXN0IG9uZSBjaGFydCB1c2luZyBgZ2dwbG90MmAgLSBDb2RlIENodW5rLgogICAgICArIERvbid0IGZvcmdldCB0byBhZGQgYGxpYnJhcnkodGlkeXZlcnNlKWAgaW4gdGhlIGZpcnN0IGNvZGUgY2h1bmsuCiAgICAtIEFuIG9ic2VydmF0aW9uIG9mIHRoZSBjaGFydCAtIGluIHlvdXIgb3duIHdvcmRzLgoKLS0tCgoyLiBMb2FkIGBnYXBtaW5kZXJgIGJ5IGBsaWJyYXJ5KGdhcG1pbmRlcilgLgoKICAgIC0gQ2hvb3NlIGBwb3BgIG9yIGBnZHBQZXJjYXBgLCBvciBib3RoLCBvbmUgY291bnRyeSBpbiB0aGUgZGF0YSwgYSBncm91cCBvZiBjb3VudHJpZXMgaW4gdGhlIGRhdGEuCiAgICAtIENyZWF0ZSBjaGFydHMgdXNpbmcgZ2dwbG90MiB3aXRoIGdlb21fbGluZSBhbmQgdGhlIHZhcmlhYmxlcyBhbmQgY291bnRyaWVzIGNob3NlbiBpbiAxLiAoU2VlIGV4YW1wbGVzIG9mIHRoZSBjaGFydHMgZm9yIGBsaWZlRXhwYC4pCiAgICAtIFN0dWR5IHRoZSBkYXRhIGFzIHlvdSBsaWtlLgogICAgLSBPYnNlcnZhdGlvbnMgYW5kIGRpZmZpY3VsdGllcyBlbmNvdW50ZXJlZC4KCioqRHVlOioqIDIwMjMtMDEtMDkgMjM6NTk6MDAuIFN1Ym1pdCB5b3VyIFIgTm90ZWJvb2sgZmlsZSBpbiBNb29kbGUgKFRoZSBTZWNvbmQgQXNzaWdubWVudCkuIER1ZSBvbiBNb25kYXkhCgotLS0KCiMjIyBPcmlnaW5hbCBEYXRhPyBXREk/CgpgYGB7cn0KZ2FwbWluZGVyCmBgYAoKLS0tCgojIyMjIFdESQoKKiBTUC5EWU4uTEUwMC5JTjogTGlmZSBleHBlY3RhbmN5IGF0IGJpcnRoLCB0b3RhbCAoeWVhcnMpCiogTlkuR0RQLlBDQVAuS0Q6IEdEUCBwZXIgY2FwaXRhIChjb25zdGFudCAyMDE1IFVTJCkKKiBTUC5QT1AuVE9UTDogUG9wdWxhdGlvbiwgdG90YWwKCmBgYHtyIGNhc2g9VFJVRX0KZGZfd2RpIDwtIFdESSgKICBjb3VudHJ5ID0gImFsbCIsIAogIGluZGljYXRvciA9IGMobGlmZUV4cCA9ICJTUC5EWU4uTEUwMC5JTiIsIHBvcCA9ICJTUC5QT1AuVE9UTCIsIGdkcFBlcmNhcCA9ICJOWS5HRFAuUENBUC5LRCIpCikKYGBgCgotLS0KCmBgYHtyfQpkZl93ZGkKYGBgCgotLS0KCmBgYHtyIGNhc2g9VFJVRX0KZGZfd2RpX2V4dHJhIDwtIFdESSgKICBjb3VudHJ5ID0gImFsbCIsIAogIGluZGljYXRvciA9IGMobGlmZUV4cCA9ICJTUC5EWU4uTEUwMC5JTiIsIHBvcCA9ICJTUC5QT1AuVE9UTCIsIGdkcFBlcmNhcCA9ICJOWS5HRFAuUENBUC5LRCIpLCAKICBleHRyYSA9IFRSVUUKKQpgYGAKCi0tLQoKYGBge3J9CmRmX3dkaV9leHRyYQpgYGAKCgojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgSUlJICAKCiMjIEltcG9ydGluZyBQdWJsaWMgRGF0YSwgV0RJCgojIyMgUmV2aWV3cyBhbmQgUHJldmlld3MKCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdhcG1pbmRlcikKbGlicmFyeShtYXBzKQpsaWJyYXJ5KFdESSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoZ2dyZXBlbCkKYGBgCgoqIFdlIGhhdmUgdXNlZCBgdGlkeXZlcnNlYCBhbmQgYGdhcG1pbmRlcmAgYWxyZWFkeS4KKiBJZiB5b3UgaGF2ZSBub3QgaW5zdGFsbGVkIGBXRElgLCBpbnN0YWxsIGl0LgoqIFdlIHdpbGwgbm90IHVzZSBgZ2dyZXBlbGAgYnV0IGlmIHlvdSB3YW50IHRvIHVzZSBpdCwgaW5zdGFsbCBpdC4KKiBgbWFwc2AgYW5kIGByZWFkeGxgIGFyZSBidW5kbGVkIGluIGB0aWR5dmVyc2VgIGJ1dCBuZWVkIHRvIGJlIGF0dGFjaGVkIGJ5IGBsaWJyYXJ5YC4KCi0tLQoKIyMjIyBHYXBtaW5kZXIgUGFja2FnZSBEYXRhCgpgYGB7cn0KZGYgPC0gZ2FwbWluZGVyCmRmCmBgYAoKLS0tCgojIyMjIGBnZHBQZXJjYXBgIG9mIEFTRUFOIGNvdW50cmllcwoKYGBge3IgZXZhbD1GQUxTRX0KYXNlYW4gPC0gYygiQnJ1bmVpIiwgIkNhbWJvZGlhIiwgIkxhb3MiLCAiTXlhbm1hciIsIAogICAgICAgICAgICJQaGlsaXBwaW5lcyIsICJJbmRvbmVzaWEiLCAiTWFsYXlzaWEiLCAiU2luZ2Fwb3JlIikKZGYgJT4lIGZpbHRlcihjb3VudHJ5ICVpbiUgYXNlYW4pICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBnZHBQZXJjYXAsIGNvbCA9IGNvdW50cnkpKSArIGdlb21fbGluZSgpCmBgYAoKLS0tCgpgYGB7ciBlY2hvPUZBTFNFfQphc2VhbiA8LSBjKCJDYW1ib2RpYSIsICJNeWFubWFyIiwgCiAgICAgICAgICAgIlBoaWxpcHBpbmVzIiwgIkluZG9uZXNpYSIsICJNYWxheXNpYSIsICJTaW5nYXBvcmUiKQpkZiAlPiUgZmlsdGVyKGNvdW50cnkgJWluJSBhc2VhbikgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGdkcFBlcmNhcCwgY29sID0gY291bnRyeSkpICsgZ2VvbV9saW5lKCkKYGBgCgoKLS0tCgpgYGB7ciBlY2hvPVRSVUV9CmRmICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGFzZWFuKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBnZHBQZXJjYXAsIHkgPSBsaWZlRXhwLCBjb2wgPSBjb3VudHJ5KSkgKyBnZW9tX3BvaW50KCkKYGBgCgotLS0KCmBgYHtyIGVjaG89VFJVRX0KZGYgJT4lIGZpbHRlcihjb3VudHJ5ICVpbiUgYXNlYW4pICU+JQogIGdncGxvdChhZXMoeCA9IGdkcFBlcmNhcCwgeSA9IGxpZmVFeHAsIGNvbCA9IGNvdW50cnkpKSArIAogIGdlb21fcG9pbnQoKSArIGNvb3JkX3RyYW5zKHggPSAibG9nMTAiLCB5ID0gImlkZW50aXR5IikKYGBgCgokXGxvZ197MTB9ezEwMH0kID0gYHIgbG9nMTAoMTAwKWAsICRcbG9nX3sxMH17MTAwMH0kID0gYHIgbG9nMTAoMTAwMClgLCAkXGxvZ197MTB9ezEwMDAwfSQgPSBgciBsb2cxMCgxMDAwMClgCgo8IS0tICQxMF57Mi41fSQgPSBgciBzcXJ0KDEwKV57NX1gLCAkMTBeezN9JCA9IGByIDEwXnszfWAsICQxMF57My41fSQgPSBgciBzcXJ0KDEwKV43YCwgIC0tPgoKPCEtLSAkMTBeezR9JCA9IGByIDEwXjRgLCAkMTBeezQuNX0kID0gYHIgc3FydCgxMCleOWAuIC0tPgoKLS0tCgpgYGB7ciBnYXBtaW5kZXItY29tYmluZWQsIGV2YWw9RkFMU0V9CmxpYnJhcnkoZ2dyZXBlbCkKZGYyMDA3IDwtIGRmICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGFzZWFuLCB5ZWFyID09IDIwMDcpCmRmICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGFzZWFuKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBnZHBQZXJjYXAsIHkgPSBsaWZlRXhwLCBjb2wgPSBjb3VudHJ5KSkrIAogIGdlb21fbGluZSgpICsgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID0gZGYyMDA3LCBhZXMobGFiZWwgPSBjb3VudHJ5KSkgKyBnZW9tX3BvaW50KCkgICsKICBjb29yZF90cmFucyh4ID0gImxvZzEwIiwgeSA9ICJpZGVudGl0eSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDEsIGhqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIkxpZmUgRXhwZWN0YW5jeSB2cyBHRFAgUGVyIENhcGl0YSBvZiBBU0VBTiBDb3VudHJpZXMiLAogICAgICAgc3VidGl0bGUgPSAiRGF0YTogZ2FwbWluZGVyIHBhY2thZ2UiLCB4ID0gIkdEUCBwZXIgQ2FwaXRhIiwgeSA9ICJMaWZlIEV4cGVjdGFuY3kiKQpgYGAKCi0tLQoKCmBgYHtyIGVjaG89RkFMU0V9CmxpYnJhcnkoZ2dyZXBlbCkKZGYyMDA3IDwtIGRmICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGFzZWFuLCB5ZWFyID09IDIwMDcpCmRmICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGFzZWFuKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBnZHBQZXJjYXAsIHkgPSBsaWZlRXhwLCBjb2wgPSBjb3VudHJ5KSkrIAogIGdlb21fbGluZSgpICsgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID0gZGYyMDA3LCBhZXMobGFiZWwgPSBjb3VudHJ5KSkgKyBnZW9tX3BvaW50KCkgICsKICBjb29yZF90cmFucyh4ID0gImxvZzEwIiwgeSA9ICJpZGVudGl0eSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDEsIGhqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIkxpZmUgRXhwZWN0YW5jeSB2cyBHRFAgUGVyIENhcGl0YSBvZiBBU0VBTiBDb3VudHJpZXMiLAogICAgICAgc3VidGl0bGUgPSAiRGF0YTogZ2FwbWluZGVyIHBhY2thZ2UiLCB4ID0gIkdEUCBwZXIgQ2FwaXRhIiwgeSA9ICJMaWZlIEV4cGVjdGFuY3kiKQpgYGAKCi0tLQoKCmBgYHtyIGVjaG89RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1hcHMpCndvcmxkX21hcCA8LSBtYXBfZGF0YSgid29ybGQiKQpkZiAlPiUKICBnZ3Bsb3QoYWVzKG1hcF9pZCA9IGNvdW50cnkpKSArIAogIGdlb21fbWFwKGFlcyhmaWxsID0gZ2RwUGVyY2FwKSwgbWFwID0gd29ybGRfbWFwKSArIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcCRsb25nLCB5ID0gd29ybGRfbWFwJGxhdCkgKwogIGxhYnModGl0bGUgPSAiR2FwbWluZGVyIFBhY2thZ2UgRGF0YSIsIHN1YnRpdGxlPSJXb3JsZCBNYXAgb2YgR0RQIHBlciBDYXBpdGEgRGF0YSIpCmBgYAoKLS0tCgojIyMjIFdvcmxkIEJhbms6IFdvcmxkIERldmVsb3BtZW50IEluZGljYXRvcnMgKFdESSkKCiogU1AuRFlOLkxFMDAuSU46IExpZmUgZXhwZWN0YW5jeSBhdCBiaXJ0aCwgdG90YWwgKHllYXJzKQoqIE5ZLkdEUC5QQ0FQLktEOiBHRFAgcGVyIGNhcGl0YSAoY29uc3RhbnQgMjAxNSBVUyQpCiogU1AuUE9QLlRPVEw6IFBvcHVsYXRpb24sIHRvdGFsCgpgYGB7ciBjYXNoPVRSVUUsIGV2YWw9RkFMU0V9CmRmX3dkaSA8LSBXREkoCiAgY291bnRyeSA9ICJhbGwiLCAKICBpbmRpY2F0b3IgPSBjKGxpZmVFeHAgPSAiU1AuRFlOLkxFMDAuSU4iLCBwb3AgPSAiU1AuUE9QLlRPVEwiLCBnZHBQZXJjYXAgPSAiTlkuR0RQLlBDQVAuS0QiKQopCmBgYAoKYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXZhbD1GQUxTRX0Kd3JpdGVfY3N2KGRmX3dkaSwgImRhdGEvZGZfd2RpLmNzdiIpCmBgYAoKYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZGZfd2RpIDwtIHJlYWRfY3N2KCJkYXRhL2RmX3dkaS5jc3YiKQpgYGAKCgotLS0KCmBgYHtyfQpkZl93ZGkKYGBgCgotLS0KCmBgYHtyIGNhc2g9VFJVRSwgZXZhbD1GQUxTRX0KZGZfd2RpX2V4dHJhIDwtIFdESSgKICBjb3VudHJ5ID0gImFsbCIsIAogIGluZGljYXRvciA9IGMobGlmZUV4cCA9ICJTUC5EWU4uTEUwMC5JTiIsIHBvcCA9ICJTUC5QT1AuVE9UTCIsIGdkcFBlcmNhcCA9ICJOWS5HRFAuUENBUC5LRCIpLCAKICBleHRyYSA9IFRSVUUKKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGV2YWw9RkFMU0V9CndyaXRlX2NzdihkZl93ZGlfZXh0cmEsICJkYXRhL2RmX3dkaV9leHRyYS5jc3YiKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmRmX3dkaV9leHRyYSA8LSByZWFkX2NzdigiZGF0YS9kZl93ZGlfZXh0cmEuY3N2IikKYGBgCgoKLS0tCgpgYGB7cn0KZGZfd2RpX2V4dHJhCmBgYAoKCi0tLQoKIyMjIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMKCiMjIyMgV2hhdCBpcyBFREEgKFBvc2l0IFByaW1lcnM6IFtWaXN1YWxpc2UgRGF0YV0oaHR0cHM6Ly9wb3NpdC5jbG91ZC9sZWFybi9wcmltZXJzLzMuMSkpCgoxLiBFREEgaXMgYW4gaXRlcmF0aXZlIGN5Y2xlIHRoYXQgaGVscHMgeW91IHVuZGVyc3RhbmQgd2hhdCB5b3VyIGRhdGEgc2F5cy4gV2hlbiB5b3UgZG8gRURBLCB5b3U6CgoyLiBHZW5lcmF0ZSBxdWVzdGlvbnMgYWJvdXQgeW91ciBkYXRhCgozLiBTZWFyY2ggZm9yIGFuc3dlcnMgYnkgdmlzdWFsaXNpbmcsIHRyYW5zZm9ybWluZywgYW5kL29yIG1vZGVsaW5nIHlvdXIgZGF0YQoKVXNlIHdoYXQgeW91IGxlYXJuIHRvIHJlZmluZSB5b3VyIHF1ZXN0aW9ucyBhbmQvb3IgZ2VuZXJhdGUgbmV3IHF1ZXN0aW9ucwoKRURBIGlzIGFuIGltcG9ydGFudCBwYXJ0IG9mIGFueSBkYXRhIGFuYWx5c2lzLiBZb3UgY2FuIHVzZSBFREEgdG8gbWFrZSBkaXNjb3ZlcmllcyBhYm91dCB0aGUgd29ybGQ7IG9yIHlvdSBjYW4gdXNlIEVEQSB0byBlbnN1cmUgdGhlIHF1YWxpdHkgb2YgeW91ciBkYXRhLCBhc2tpbmcgcXVlc3Rpb25zIGFib3V0IHdoZXRoZXIgdGhlIGRhdGEgbWVldHMgeW91ciBzdGFuZGFyZHMgb3Igbm90LgoKLS0tCgojIyMgT3BlbiBhbmQgUHVibGljIERhdGEsIFdvcmxkIEJhbmsKCiMjIyMgW09wZW4gR292ZXJubWVudCBEYXRhIFRvb2xraXRdKGh0dHA6Ly9vcGVuZGF0YXRvb2xraXQud29ybGRiYW5rLm9yZyk6IFtPcGVuIERhdGEgRGVmaW5lZF0oaHR0cDovL29wZW5kYXRhdG9vbGtpdC53b3JsZGJhbmsub3JnL2VuL2Vzc2VudGlhbHMuaHRtbCkKClRoZSB0ZXJtICoqT3BlbiBEYXRhKiogaGFzIGEgdmVyeSBwcmVjaXNlIG1lYW5pbmcuIERhdGEgb3IgY29udGVudCBpcyBvcGVuIGlmIGFueW9uZSBpcyBmcmVlIHRvIHVzZSwgcmUtdXNlIG9yIHJlZGlzdHJpYnV0ZSBpdCwgc3ViamVjdCBhdCBtb3N0IHRvIG1lYXN1cmVzIHRoYXQgcHJlc2VydmUgcHJvdmVuYW5jZSBhbmQgb3Blbm5lc3MuCgoxLiBUaGUgZGF0YSBtdXN0IGJlIF9sZWdhbGx5IG9wZW5fLCB3aGljaCBtZWFucyB0aGV5IG11c3QgYmUgcGxhY2VkIGluIHRoZSBwdWJsaWMgZG9tYWluIG9yIHVuZGVyIGxpYmVyYWwgdGVybXMgb2YgdXNlIHdpdGggbWluaW1hbCByZXN0cmljdGlvbnMuCjIuIFRoZSBkYXRhIG11c3QgYmUgX3RlY2huaWNhbGx5IG9wZW5fLCB3aGljaCBtZWFucyB0aGV5IG11c3QgYmUgcHVibGlzaGVkIGluIGVsZWN0cm9uaWMgZm9ybWF0cyB0aGF0IGFyZSBtYWNoaW5lIHJlYWRhYmxlIGFuZCBub24tcHJvcHJpZXRhcnksIHNvIHRoYXQgYW55b25lIGNhbiBhY2Nlc3MgYW5kIHVzZSB0aGUgZGF0YSB1c2luZyBjb21tb24sIGZyZWVseSBhdmFpbGFibGUgc29mdHdhcmUgdG9vbHMuIERhdGEgbXVzdCBhbHNvIGJlIHB1YmxpY2x5IGF2YWlsYWJsZSBhbmQgYWNjZXNzaWJsZSBvbiBhIHB1YmxpYyBzZXJ2ZXIsIHdpdGhvdXQgcGFzc3dvcmQgb3IgZmlyZXdhbGwgcmVzdHJpY3Rpb25zLiBUbyBtYWtlIE9wZW4gRGF0YSBlYXNpZXIgdG8gZmluZCwgbW9zdCBvcmdhbml6YXRpb25zIGNyZWF0ZSBhbmQgbWFuYWdlIE9wZW4gRGF0YSBjYXRhbG9ncy4KCi0tLQoKIyMjIFdvcmxkIEJhbms6IFdESSAtIFdvcmxkIERldmVsb3BtZW50IEluZGljYXRlcnMKCiogV29ybGQgQmFuazogaHR0cHM6Ly93d3cud29ybGRiYW5rLm9yZwoqIFtXaG8gd2UgYXJlXShodHRwczovL3d3dy53b3JsZGJhbmsub3JnL2VuL3doby13ZS1hcmUpOgogIC0gVG8gZW5kIGV4dHJlbWUgcG92ZXJ0eTogQnkgcmVkdWNpbmcgdGhlIHNoYXJlIG9mIHRoZSBnbG9iYWwgcG9wdWxhdGlvbiB0aGF0IGxpdmVzIGluIGV4dHJlbWUgcG92ZXJ0eSB0byAzIHBlcmNlbnQgYnkgMjAzMC4KICAtIFRvIHByb21vdGUgc2hhcmVkIHByb3NwZXJpdHk6IEJ5IGluY3JlYXNpbmcgdGhlIGluY29tZXMgb2YgdGhlIHBvb3Jlc3QgNDAgcGVyY2VudCBvZiBwZW9wbGUgaW4gZXZlcnkgY291bnRyeS4gCiogV29ybGQgQmFuayBPcGVuIERhdGE6IGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnCiAgLSBEYXRhIEJhbmssIFdvcmxkIERldmVsb3BtZW50IEluZGljYXRvcnMsIGV0Yy4KKiBbV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyAoV0RJKV0oaHR0cHM6Ly9kYXRhdG9waWNzLndvcmxkYmFuay5vcmcvd29ybGQtZGV2ZWxvcG1lbnQtaW5kaWNhdG9ycy8pIDogdGhlIFdvcmxkIEJhbmvigJlzIHByZW1pZXIgY29tcGlsYXRpb24gb2YgY3Jvc3MtY291bnRyeSBjb21wYXJhYmxlIGRhdGEgb24gZGV2ZWxvcG1lbnQ7IDE0MDAgdGltZSBzZXJpZXMgaW5kaWNhdG9ycwogIC0gVGhlbWVzOiBQb3ZlcnR5IGFuZCBJbmVxdWFsaXR5LCBQZW9wbGUsIEVudmlyb25tZW50LCBFY29ub215LCBTdGF0ZXMgYW5kIE1hcmtldHMsIEdsb2JhbCBMaW5rcwogIC0gT3BlbiBEYXRhICYgRGF0YUJhbms6IEV4cGxvcmUgZGF0YSwgUXVlcnkgZGF0YWJhc2UKICAtIEJ1bGsgRG93bmxvYWQ6IEV4Y2VsLCBDU1YKICAtIEFQSSBEb2N1bWVudGF0aW9uCiAgCi0tLQoKIyMjIFIgUGFja2FnZSBbV0RJXShodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPVdESSkKCiogW1dESV0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1XREkpOiBXb3JsZCBEZXZlbG9wbWVudCBJbmRpY2F0b3JzIGFuZCBPdGhlciBXb3JsZCBCYW5rIERhdGEKKiBTZWFyY2ggYW5kIGRvd25sb2FkIGRhdGEgZnJvbSBvdmVyIDQwIGRhdGFiYXNlcyBob3N0ZWQgYnkgdGhlIFdvcmxkIEJhbmssIGluY2x1ZGluZyB0aGUgV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyAoJ1dESScpLCBJbnRlcm5hdGlvbmFsIERlYnQgU3RhdGlzdGljcywgRG9pbmcgQnVzaW5lc3MsIEh1bWFuIENhcGl0YWwgSW5kZXgsIGFuZCBTdWItbmF0aW9uYWwgUG92ZXJ0eSBpbmRpY2F0b3JzLgoqIFZlcnNpb246IDIuNy40CiogTWF0ZXJpYWxzOglbUkVBRE1FXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvV0RJL3JlYWRtZS9SRUFETUUuaHRtbCkgICAtIF91c2FnZV8KICAtIFtORVdTXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvV0RJL25ld3MvbmV3cy5odG1sKSAtIF92ZXJzaW9uIGhpc3RvcnlfCiogUHVibGlzaGVkOiAyMDIxLTA0LTA2CiogUkVBRE1FOiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvV0RJL3JlYWRtZS9SRUFETUUuaHRtbAoqIFJlZmVyZW5jZSBtYW51YWw6CVtXREkucGRmXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvV0RJL1dESS5wZGYpCgotLS0KCiMjIyBGdW5jdGlvbiBXREkKCiogKipVc2FnZSoqCgpgYGAKV0RJKGNvdW50cnkgPSAiYWxsIiwKICAgIGluZGljYXRvciA9ICJOWS5HRFAuUENBUC5LRCIsCiAgICBzdGFydCA9IDE5NjAsCiAgICBlbmQgPSAyMDIwLAogICAgZXh0cmEgPSBGQUxTRSwKICAgIGNhY2hlID0gTlVMTCkKYGBgCgoqICoqQXJndW1lbnRzKiogU2VlIEhlbHAhCiAgLSBjb3VudHJ5OiBWZWN0b3Igb2YgY291bnRyaWVzIChJU08tMiBjaGFyYWN0ZXIgY29kZXMsIGUuZy4gIkJSIiwgIlVTIiwgIkNBIiwgb3IgImFsbCIpIAogIC0gaW5kaWNhdG9yOiBJZiB5b3Ugc3VwcGx5IGEgbmFtZWQgdmVjdG9yLCB0aGUgaW5kaWNhdG9ycyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgcmVuYW1lZDogYGMoJ3dvbWVuX3ByaXZhdGVfc2VjdG9yJyA9ICdCSS5QV0suUFJWUy5GRS5aUycpYAoKLS0tCgojIyMgRnVuY3Rpb24gV0RJc2VhcmNoCgpgYGB7cn0KbGlicmFyeShXREkpCmBgYApgYGB7cn0KV0RJc2VhcmNoKHN0cmluZyA9ICJOWS5HRFAuUENBUC5LRCIsIAogICAgICAgICAgZmllbGQgPSAiaW5kaWNhdG9yIiwgY2FjaGUgPSBOVUxMKQpgYGAKCi0tLQoKYGBge3J9CldESXNlYXJjaChzdHJpbmcgPSAicG9wdWxhdGlvbiIsIAogICAgICAgICAgZmllbGQgPSAibmFtZSIsIHNob3J0PUZBTFNFLCBjYWNoZSA9IE5VTEwpCmBgYAoKLS0tCgpgYGAKV0RJc2VhcmNoKHN0cmluZyA9ICJOWS5HRFAuUENBUC5LRCIsIAogIGZpZWxkID0gImluZGljYXRvciIsIHNob3J0ID0gRkFMU0UsIGNhY2hlID0gTlVMTCkKYGBgCmBgYApXRElzZWFyY2goc3RyaW5nID0gImdkcCIsIAogIGZpZWxkID0gIm5hbWUiLCBzaG9ydCA9IFRSVUUsIGNhY2hlID0gTlVMTCkgCmBgYAoKLS0tCgojIyMgQnVsayBEb3dubG9hZHMgYXQgV0RJIHNpdGUKCldESWJ1bGsgZG93bmxvYWRzIHRoZSB6aXAgZmlsZSBvZiBCdWxrIERvd25sb2FkcyBpbiBbV0RJIHNpdGVdKGh0dHBzOi8vZGF0YXRvcGljcy53b3JsZGJhbmsub3JnL3dvcmxkLWRldmVsb3BtZW50LWluZGljYXRvcnMvKSAsIGl0IGlzIGEgbGlzdCBjb250YWluaW5nIDYgZGF0YSBmcmFtZXM6IERhdGEsIENvdW50cnksIFNlcmllcywgQ291bnRyeS1TZXJpZXMsIFNlcmllcy1UaW1lLCBGb290Tm90ZS4KCi0tLQoKIyMjIFdESWNhY2hlCgpEb3dubG9hZCBhbiB1cGRhdGVkIGxpc3Qgb2YgYXZhaWxhYmxlIFdESSBpbmRpY2F0b3JzIGZyb20gdGhlIFdvcmxkIEJhbmsgd2Vic2l0ZS4gUmV0dXJucyBhIGxpc3QgZm9yIHVzZSBpbiB0aGUgV0RJc2VhcmNoIGZ1bmN0aW9uLgoKYGBge3Igd2lkY2FjaGUsIGNhc2g9VFJVRSwgZXZhbD1GQUxTRX0Kd2RpX2NhY2hlIDwtIFdESWNhY2hlKCkKYGBgCgpEb3dubG9hZGluZyBhbGwgc2VyaWVzIGluZm9ybWF0aW9uIGZyb20gdGhlIFdvcmxkIEJhbmsgd2Vic2l0ZSBjYW4gdGFrZSB0aW1lLiBUaGUgV0RJIHBhY2thZ2Ugc2hpcHMgd2l0aCBhIGxvY2FsIGRhdGEgb2JqZWN0IHdpdGggaW5mb3JtYXRpb24gb24gYWxsIHRoZSBzZXJpZXMgYXZhaWxhYmxlIG9uIDIwMTItMDYtMTguIFlvdSBjYW4gdXBkYXRlIHRoaXMgZGF0YWJhc2UgYnkgcmV0cmlldmluZyBhIG5ldyBsaXN0IHVzaW5nIGBXREljYWNoZWAsIGFuZCB0aGVuIGZlZWRpbmcgdGhlIHJlc3VsdGluZyBvYmplY3QgdG8gYFdESXNlYXJjaGAgdmlhIHRoZSBjYWNoZSBhcmd1bWVudC4KCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGV2YWw9RkFMU0V9CndyaXRlX3Jkcyh3ZGlfY2FjaGUsICJkYXRhL3dkaV9jYWNoZS5SRGF0YSIsIHJlZmhvb2sgPSBOVUxMKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGV2YWw9RkFMU0V9CndkaV9jYWNoZSA8LSByZWFkX3JkcygiZGF0YS93ZGlfY2FjaGUuUkRhdGEiLCByZWZob29rID0gTlVMTCkKYGBgCgoKCi0tLQoKYGBge3IgZXZhbD1GQUxTRX0Kd2RpX2NhY2hlCmBgYAoKCi0tLQoKIyMjIFdESV9kYXRhCgpMaXN0IG9mIDIgZGF0YSBmcmFtZXMKClRoZSBmaXJzdCBjaGFyYWN0ZXIgbWF0cml4IGluY2x1ZGVzIGEgZnVsbCBsaXN0IG9mIFdESSBzZXJpZXMuIFRoaXMgbGlzdCBpcyB1cGRhdGVkIHNlbWktcmVndWxhcmx5LiBVc2VycyBjYW4gcmVmcmVzaCB0aGUgbGlzdCBtYW51YWxseSB1c2luZyB0aGUgJ1dESWNhY2hlKCknIGZ1bmN0aW9uIGFuZCBzZWFyY2ggaW4gdGhlIHVwZGF0ZWQgbGlzdCB1c2luZyB0aGUgJ2NhY2hlJyBhcmd1bWVudC4KCgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBnbGltcHNlKFdESV9kYXRhKSAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tIC0tLSAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIFdESV9kYXRhJHNlcmllcyAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tIC0tLSAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIFdESV9kYXRhJGNvdW50cnkgLS0+CjwhLS0gYGBgIC0tPgoKYGBge3J9CldESV9kYXRhJGNvdW50cnkgICU+JSBmaWx0ZXIoY291bnRyeSA9PSAiSmFwYW4iKQpgYGAKCi0tLQoKYGBge3J9CldESXNlYXJjaChzdHJpbmcgPSAiZ2RwIiwgCiAgZmllbGQgPSAibmFtZSIsIHNob3J0ID0gRkFMU0UsIGNhY2hlID0gTlVMTCkgI2NhY2hlID0gd2RpX2NhY2hlCmBgYAoKLS0tCgojIyMgV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyAtIFN1bW1hcnkKCkZpbmQgaW5kaWNhdG9yczoKCjEuIGBXRElzZWFyY2goc3RyaW5nID0gImdkcCIsIGZpZWxkID0gIm5hbWUiLCBzaG9ydCA9IEZBTFNFLCBjYWNoZSA9IE5VTEwpYAogIC0gYFdESXNlYXJjaChzdHJpbmcgPSAiZ2RwIiwgZmllbGQgPSAibmFtZSIsIHNob3J0ID0gRkFMU0UsIGNhY2hlID0gd2RpX2NhY2hlKWAKICAtIGBXRElzZWFyY2goc3RyaW5nID0gIk5ZLkdEUC5QQ0FQLktEIiwgZmllbGQgPSAiaW5kaWNhdG9yIiwgc2hvcnQgPSBGQUxTRSwgY2FjaGUgPSBOVUxMKWAKMi4gW1dESV0oaHR0cHM6Ly9kYXRhdG9waWNzLndvcmxkYmFuay5vcmcvd29ybGQtZGV2ZWxvcG1lbnQtaW5kaWNhdG9ycy8pOiBEYXRhIFRoZW1lcwozLiBCcm93c2UgYnkgSW5kaWNhdG9yczogaHR0cHM6Ly9kYXRhLndvcmxkYmFuay5vcmcvaW5kaWNhdG9yCiAgIC0gRmVhdHVyZWQgSW5kaWNhdG9ycyBvciBBbGwgSW5kaWNhdG9ycwogICAtIE9idGFpbiB0aGUgaW5kaWNhdG9yIGZyb20gdGhlIGRldGFpbCBvciB0aGUgVVJMCgotLS0KCiMjIyMgRXhhbXBsZTogQ08yIGVtaXNzaW9ucyAobWV0cmljIHRvbnMgcGVyIGNhcGl0YSkKCiogSUQ6IEVOLkFUTS5DTzJFLlBDCiogVVJMOiBodHRwczovL2RhdGEud29ybGRiYW5rLm9yZy9pbmRpY2F0b3IvRU4uQVRNLkNPMkUuUEMKCmBgYHtyfQpXRElzZWFyY2goc3RyaW5nID0gIkVOLkFUTS5DTzJFLlBDIiwgZmllbGQgPSAiaW5kaWNhdG9yIiwgCiAgICAgICAgICBzaG9ydCA9IEZBTFNFLCBjYWNoZSA9IE5VTEwpICNjYWNoZSA9IHdkaV9jYWNoZQpgYGAKCmBgYHtyfQpXRElzZWFyY2goc3RyaW5nID0gIkVOLkFUTS5DTzJFLlBDIiwgZmllbGQgPSAiaW5kaWNhdG9yIiwgCiAgICAgICAgICBzaG9ydCA9IEZBTFNFLCBjYWNoZSA9IE5VTEwpICU+JSBwdWxsKGRlc2NyaXB0aW9uKSAjY2FjaGUgPSB3ZGlfY2FjaGUKYGBgCgoqIFNvdXJjZTogQ2xpbWF0ZSBXYXRjaC4gMjAyMC4gR0hHIEVtaXNzaW9ucy4gV2FzaGluZ3RvbiwgREM6IFdvcmxkIFJlc291cmNlcyBJbnN0aXR1dGUuIEF2YWlsYWJsZSBhdDogY2xpbWF0ZXdhdGNoZGF0YS5vcmcvZ2hnLWVtaXNzaW9ucy4gU2VlIFNQLlBPUC5UT1RMIGZvciB0aGUgZGVub21pbmF0b3IncyBzb3VyY2UuCgoKCgotLS0KCmBgYHtyIGNhc2g9VFJVRSwgZXZhbD1GQUxTRX0KY28ycGNhcCA8LSBXREkoY291bnRyeSA9ICJhbGwiLCBpbmRpY2F0b3IgPSAiRU4uQVRNLkNPMkUuUEMiLCBzdGFydCA9IDE5NjAsIGVuZCA9IE5VTEwsIGV4dHJhID0gVFJVRSwgY2FjaGUgPSBOVUxMKSAjY2FjaGUgPSB3ZGlfY2FjaGUKYGBgCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBldmFsPUZBTFNFfQp3cml0ZV9jc3YoY28ycGNhcCwgImRhdGEvY28ycGNhcC5jc3YiKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGV2YWw9RkFMU0V9CmNvMnBjYXAgPC0gcmVhZF9jc3YoImRhdGEvY28ycGNhcC5jc3YiKQpgYGAKCmBgYHtyfQpjbzJwY2FwCmBgYAoKCi0tLQoKYGBge3J9CndyaXRlX2NzdihjbzJwY2FwLCAiZGF0YS9jbzJwY2FwLmNzdiIpCmBgYAoKCi0tLQoKYGBge3J9CmNvMnBjYXAgJT4lIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiV29ybGQiLCAiSmFwYW4iLCAiVW5pdGVkIFN0YXRlcyIsICJDaGluYSIpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gRU4uQVRNLkNPMkUuUEMsIGNvbG9yID0gY291bnRyeSkpICsgCiAgZ2VvbV9saW5lKCkKYGBgCgotLS0KCmBgYHtyfQpjbzJwY2FwICU+JSBmaWx0ZXIoIWlzLm5hKEVOLkFUTS5DTzJFLlBDKSkgJT4lIHB1bGwoeWVhcikgJT4lIHN1bW1hcnkoKQpgYGAKCgoKCi0tLQoKYGBge3J9CmNvMnBjYXAgJT4lIAogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiV29ybGQiLCAiSmFwYW4iLCAiVW5pdGVkIFN0YXRlcyIsICJDaGluYSIpLCB5ZWFyICVpbiUgMTk5MDoyMDE5KSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gRU4uQVRNLkNPMkUuUEMsIGNvbG9yID0gY291bnRyeSkpICsgCiAgZ2VvbV9saW5lKCkKYGBgCgotLS0KCmBgYHtyfQpjbzJwY2FwICU+JSAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgeWVhciA9PSAyMDE5KSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBpbmNvbWUsIHkgPSBFTi5BVE0uQ08yRS5QQywgZmlsbCA9IGluY29tZSkpICsgCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgotLS0KCmBgYHtyfQpjbzJwY2FwICU+JSAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgeWVhciA9PSAyMDE5LCAhaXMubmEoRU4uQVRNLkNPMkUuUEMpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBpbmNvbWUsIHkgPSBFTi5BVE0uQ08yRS5QQywgZmlsbCA9IGluY29tZSkpICsgCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgoqIFdoYXQgaXMgYGJveHBsb3RgOiBodHRwczovL3ZpbWVvLmNvbS8yMjIzNTgwMzQKCi0tLQoKYGBge3J9CmNvMnBjYXAgJT4lIAogIGZpbHRlcihpbmNvbWUgIT0gIkFnZ3JlZ2F0ZXMiLCB5ZWFyID09IDIwMTksICFpcy5uYShFTi5BVE0uQ08yRS5QQykpICU+JQogIGdyb3VwX2J5KGluY29tZSkgJT4lCiAgc3VtbWFyaXplKG1pbiA9IG1pbihFTi5BVE0uQ08yRS5QQyksIG1lZCA9IG1lZGlhbihFTi5BVE0uQ08yRS5QQyksIG1heCA9IG1heChFTi5BVE0uQ08yRS5QQyksIElRUiA9IElRUihFTi5BVE0uQ08yRS5QQyksIG4gPSBuKCkpCmBgYAoKLS0tCmBgYHtyfQpjbzJwY2FwICU+JSAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgeWVhciA9PSAyMDE5LCAhaXMubmEoRU4uQVRNLkNPMkUuUEMpKSAlPiUKICBmaWx0ZXIoIWluY29tZSAlaW4lIGMoIkhpZ2ggaW5jb21lIiwgIkxvdyBpbmNvbWUiLCAiTG93ZXIgbWlkZGxlIGluY29tZSIsICJVcHBlciBtaWRkbGUgaW5jb21lIikpCmBgYAoKYGBge3J9CmNvMnBjYXAgJT4lIAogIGZpbHRlcihpbmNvbWUgIT0gIkFnZ3JlZ2F0ZXMiLCB5ZWFyID09IDIwMTkpICU+JQogIGZpbHRlcihpbmNvbWUgPT0gIk5vdCBjbGFzc2lmaWVkIikKYGBgCgotLS0KCmBgYHtyIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0KY28ycGNhcCAlPiUgCiAgZmlsdGVyKGluY29tZSAhPSAiQWdncmVnYXRlcyIsIHllYXIgPT0gMjAxOSkgJT4lCiAgZ2dwbG90KGFlcyhtYXBfaWQgPSBjb3VudHJ5KSkgKyAKICBnZW9tX21hcChhZXMoZmlsbCA9IGluY29tZSksIG1hcCA9IHdvcmxkX21hcCkgKyBleHBhbmRfbGltaXRzKHggPSB3b3JsZF9tYXAkbG9uZywgeSA9IHdvcmxkX21hcCRsYXQpICsKICBsYWJzKHRpdGxlID0gIkluY29tZSBMZXZlbHMgaW4gMjAxOSIpCmBgYAotLS0KCmBgYHtyIGVjaG89RkFMU0V9CmNvMnBjYXAgJT4lIAogIGZpbHRlcihpbmNvbWUgIT0gIkFnZ3JlZ2F0ZXMiLCB5ZWFyID09IDIwMTkpICU+JQogIGdncGxvdChhZXMobWFwX2lkID0gY291bnRyeSkpICsgCiAgZ2VvbV9tYXAoYWVzKGZpbGwgPSBpbmNvbWUpLCBtYXAgPSB3b3JsZF9tYXApICsgZXhwYW5kX2xpbWl0cyh4ID0gd29ybGRfbWFwJGxvbmcsIHkgPSB3b3JsZF9tYXAkbGF0KSArCiAgbGFicyh0aXRsZSA9ICJJbmNvbWUgTGV2ZWxzIGluIDIwMTkiKQpgYGAKCi0tLQoKYGBge3J9CmNvMnBjYXAgJT4lIGRpc3RpbmN0KGNvdW50cnkpCmBgYAoKLS0tCgpgYGB7cn0Kd29ybGRfbWFwICU+JSBkaXN0aW5jdChyZWdpb24pCmBgYAoKLS0tCgpgYGB7cn0Kd29ybGRfbWFwMCA8LSB3b3JsZF9tYXAgJT4lIAogIG11dGF0ZShyZWdpb24gPSBjYXNlX3doZW4ocmVnaW9uID09ICJNYWNlZG9uaWEiIH4gIk5vcnRoIE1hY2Vkb25pYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkl2b3J5IENvYXN0IiAgfiAiQ290ZSBkJ0l2b2lyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkRlbW9jcmF0aWMgUmVwdWJsaWMgb2YgdGhlIENvbmdvIiAgfiAiQ29uZ28sIERlbS4gUmVwLiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIlJlcHVibGljIG9mIENvbmdvIiB+ICAiQ29uZ28sIFJlcC4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJVSyIgfiAgIlVuaXRlZCBLaW5nZG9tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiVVNBIiB+ICAiVW5pdGVkIFN0YXRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkxhb3MiIH4gICJMYW8gUERSIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiU2xvdmFraWEiIH4gICJTbG92YWsgUmVwdWJsaWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJTYWludCBMdWNpYSIgfiAgIlN0LiBMdWNpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkt5cmd5enN0YW4iICB+ICAiS3lyZ3l6IFJlcHVibGljIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiTWljcm9uZXNpYSIgfiAiTWljcm9uZXNpYSwgRmVkLiBTdHMuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiU3dhemlsYW5kIiAgfiAiRXN3YXRpbmkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiVmlyZ2luIElzbGFuZHMiICB+ICJWaXJnaW4gSXNsYW5kcyAoVS5TLikiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiUnVzc2lhIiB+ICJSdXNzaWFuIEZlZGVyYXRpb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiRWd5cHQiIH4gIkVneXB0LCBBcmFiIFJlcC4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJTb3V0aCBLb3JlYSIgfiAiS29yZWEsIFJlcC4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJOb3J0aCBLb3JlYSIgfiAiS29yZWEsIERlbS4gUGVvcGxlJ3MgUmVwLiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIklyYW4iIH4gIklyYW4sIElzbGFtaWMgUmVwLiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkJydW5laSIgfiAiQnJ1bmVpIERhcnVzc2FsYW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJWZW5lenVlbGEiIH4gIlZlbmV6dWVsYSwgUkIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJZZW1lbiIgfiAiWWVtZW4sIFJlcC4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJCYWhhbWFzIiB+ICJCYWhhbWFzLCBUaGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJTeXJpYSIgfiAiU3lyaWFuIEFyYWIgUmVwdWJsaWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJUdXJrZXkiIH4gIlR1cmtpeWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJDYXBlIFZlcmRlIiB+ICJDYWJvIFZlcmRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiR2FtYmlhIiB+ICJHYW1iaWEsIFRoZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkN6ZWNoIFJlcHVibGljIiB+ICJDemVjaGlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiByZWdpb24pKQpgYGAKCi0tLQoKYGBge3J9CndyaXRlX2Nzdih3b3JsZF9tYXAwLCAiZGF0YS93b3JsZF9tYXAwLmNzdiIpCmBgYAoKYGBge3IgZXZhbD1GQUxTRX0KbWFwMF91cmwgPC0gImh0dHBzOi8vaWN1LWhzdXp1a2kuZ2l0aHViLmlvL2RhNHIyMDIyX25vdGUvZGF0YS93b3JsZF9tYXAwLmNzdiIKd29ybGRfbWFwMCA8LSByZWFkX2NzdihtYXAwX3VybCkKYGBgCgoKLS0tCgpgYGB7cn0KY28ycGNhcCAlPiUgZmlsdGVyKGluY29tZSAhPSAiQWdncmVnYXRlcyIsIHllYXIgPT0gMjAxOSkgJT4lIAogIGFudGlfam9pbih3b3JsZF9tYXAwLCBieSA9IGMoImNvdW50cnkiPSJyZWdpb24iKSkKYGBgCgotLS0KCmBgYHtyfQp3b3JsZF9tYXAwICU+JSBhbnRpX2pvaW4oY28ycGNhcCwgYnkgPSBjKCJyZWdpb24iPSJjb3VudHJ5IikpICU+JSBkaXN0aW5jdChyZWdpb24pICU+JSBhcnJhbmdlKHJlZ2lvbikKYGBgCgotLS0KCgoKYGBge3J9CndvcmxkX21hcDAgJT4lIGxlZnRfam9pbihpc28zMTY2LCBieSA9IGMoInJlZ2lvbiIgPSAiSVNPbmFtZSIpKSAlPiUKICBmaWx0ZXIoaXMubmEoYTIpKSAlPiUgZGlzdGluY3QocmVnaW9uKQpgYGAKCgotLS0KCgpgYGB7ciBlY2hvPUZBTFNFfQpjbzJwY2FwICU+JSAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgeWVhciA9PSAyMDE5KSAlPiUKICBnZ3Bsb3QoYWVzKG1hcF9pZCA9IGNvdW50cnkpKSArIAogIGdlb21fbWFwKGFlcyhmaWxsID0gaW5jb21lKSwgbWFwID0gd29ybGRfbWFwMCkgKyBleHBhbmRfbGltaXRzKHggPSB3b3JsZF9tYXAkbG9uZywgeSA9IHdvcmxkX21hcCRsYXQpICsKICBsYWJzKHRpdGxlID0gIkluY29tZSBMZXZlbHMgaW4gMjAxOSIpCmBgYAoKCgoKIyMgRGF0YSBWaXN1YWxpemF0aW9uIGFuZCBgZ2dwbG90MicKCgojIyMgTGVhcm5pbmcgUmVzb3VjZXMKCiogUG9zaXQgUHJpbWVyczoKICAtIFtWaXN1YWxpemUgRGF0YV0oaHR0cHM6Ly9wb3NpdC5jbG91ZC9sZWFybi9wcmltZXJzLzMpOiBMZWFybiBob3cgdG8gdXNlIGdncGxvdDIgdG8gbWFrZSBhbnkgdHlwZSBvZiBwbG90IHdpdGggeW91ciBkYXRhLiBUaGVuIGxlYXJuIHRoZSBiZXN0IHdheXMgdG8gdmlzdWFsaXplIHBhdHRlcm5zIHdpdGhpbiB2YWx1ZXMgYW5kIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMuCiogW3I0ZHM6IERhdGEgVmlzdWFsaXphdGlvbl0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9kYXRhLXZpc3VhbGlzYXRpb24uaHRtbCNkYXRhLXZpc3VhbGlzYXRpb24pCgotLS0KCiMjIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCgojIyMjIFdoYXQgaXMgRURBPwoKRURBIGlzIGFuIGl0ZXJhdGl2ZSBjeWNsZSB0aGF0IGhlbHBzIHlvdSB1bmRlcnN0YW5kIHdoYXQgeW91ciBkYXRhIHNheXMuIFdoZW4geW91IGRvIEVEQSwgeW91OgoKMS4gR2VuZXJhdGUgcXVlc3Rpb25zIGFib3V0IHlvdXIgZGF0YQoKMi4gU2VhcmNoIGZvciBhbnN3ZXJzIGJ5IHZpc3VhbGlzaW5nLCB0cmFuc2Zvcm1pbmcsIGFuZC9vciBtb2RlbGluZyB5b3VyIGRhdGEKCjMuIFVzZSB3aGF0IHlvdSBsZWFybiB0byByZWZpbmUgeW91ciBxdWVzdGlvbnMgYW5kL29yIGdlbmVyYXRlIG5ldyBxdWVzdGlvbnMKCkVEQSBpcyBhbiBpbXBvcnRhbnQgcGFydCBvZiBhbnkgZGF0YSBhbmFseXNpcy4gWW91IGNhbiB1c2UgRURBIHRvIG1ha2UgZGlzY292ZXJpZXMgYWJvdXQgdGhlIHdvcmxkOyBvciB5b3UgY2FuIHVzZSBFREEgdG8gZW5zdXJlIHRoZSBxdWFsaXR5IG9mIHlvdXIgZGF0YSwgYXNraW5nIHF1ZXN0aW9ucyBhYm91dCB3aGV0aGVyIHRoZSBkYXRhIG1lZXRzIHlvdXIgc3RhbmRhcmRzIG9yIG5vdC4KCi0tLQoKIyMjIyBUd28gdXNlZnVsIHF1ZXN0aW9ucwoKVGhlcmUgaXMgbm8gcnVsZSBhYm91dCB3aGljaCBxdWVzdGlvbnMgeW91IHNob3VsZCBhc2sgdG8gZ3VpZGUgeW91ciByZXNlYXJjaC4gSG93ZXZlciwgdHdvIHR5cGVzIG9mIHF1ZXN0aW9ucyB3aWxsIGFsd2F5cyBiZSB1c2VmdWwgZm9yIG1ha2luZyBkaXNjb3ZlcmllcyB3aXRoaW4geW91ciBkYXRhLiBZb3UgY2FuIGxvb3NlbHkgd29yZCB0aGVzZSBxdWVzdGlvbnMgYXM6CgoxLiBXaGF0IHR5cGUgb2YgdmFyaWF0aW9uIG9jY3VycyB3aXRoaW4gbXkgdmFyaWFibGVzPwoyLiBXaGF0IHR5cGUgb2YgY292YXJpYXRpb24gb2NjdXJzIGJldHdlZW4gbXkgdmFyaWFibGVzPwoKVGhlIHJlc3Qgb2YgdGhpcyB0dXRvcmlhbCB3aWxsIGxvb2sgYXQgdGhlc2UgdHdvIHF1ZXN0aW9ucy4gVG8gbWFrZSB0aGUgZGlzY3Vzc2lvbiBlYXNpZXIsIGxldOKAmXMgZGVmaW5lIHNvbWUgdGVybXPigKYKCi0tLQoKIyMjIERhdGEgVmlzdWFsaXphdGlvbgoKIyMjIGBnZ3Bsb3QyYCBCYXNpY3MKCiFbdmlzdWFsaXphdGlvbl0oZGF0YS92aXN1YWxpemF0aW9uLnBuZyl7d2lkdGg9NzUlfQoKCi0tLQoKIyMjIEV4YW1wbGU6IFdvcmxkIEluZXF1aWxpdHkgUmVwb3J0IC0gV0lSMjAyMgoKKiBXb3JsZCBJbmVxdWFsaXR5IFJlcG9ydDogaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC8KKiBFeGVjdXRpdmUgU3VtbWFyeTogaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC9leGVjdXRpdmUtc3VtbWFyeS8KKiBNZXRob2RvbG9neTogaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC9tZXRob2RvbG9neS8KKiBEYXRhIFVSTDogaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC93d3ctc2l0ZS91cGxvYWRzLzIwMjIvMDMvV0lSMjAyMlRhYmxlc0ZpZ3VyZXMtU3VtbWFyeS54bHN4CgpgYGB7cn0KbGlicmFyeShyZWFkeGwpCmBgYAoKYGBge3Igc3VtbWFyeS1kYXRhLCBjYXNoID0gVFJVRSwgZXZhbCA9IEZBTFNFfQp1cmxfc3VtbWFyeSA8LSAiaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC93d3ctc2l0ZS91cGxvYWRzLzIwMjIvMDMvV0lSMjAyMlRhYmxlc0ZpZ3VyZXMtU3VtbWFyeS54bHN4Igpkb3dubG9hZC5maWxlKHVybCA9IHVybF9zdW1tYXJ5LCBkZXN0ZmlsZSA9ICJkYXRhL1dJUjIwMjJzLnhsc3giKSAKZXhjZWxfc2hlZXRzKCJkYXRhL1dJUjIwMjJzLnhsc3giKQpgYGAKCiMjIyBGMTQ6IEdsb2JhbCBjYXJib24gaW5lcXVhbGl0eSwgMjAxOS4gR3JvdXAgY29udHJpYnV0aW9uIHRvIHdvcmxkIGVtaXNzaW9ucyAoJSkKCk5vdGUgdGhhdCB0aGUgc2hlZXQgbmFtZSBvZiBGMTQgaGFzIHBlcmlvZCBhdCB0aGUgZW5kLiAKCmBgYHtyIGRhdGEtZjE0LCBjYXNoID0gVFJVRX0KZGZfZjE0IDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjE0LiIpCmRmX2YxNApgYGAKCiogYFxuYCBmb3IgbGluZSBicmVhayBpbiB0aGUgdGl0bGUuCgotLS0KCiMjIyMgQ2F0ZWdvcmljYWwgdnMgQ29udGludW91cyBWYWx1ZQoKYGBge3J9CmRmX2YxNCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gR3JvdXAsIHkgPSBTaGFyZSkpICsKICBnZW9tX2NvbCgpCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjE0ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBHcm91cCwgeSA9IFNoYXJlKSkgKwogIGdlb21fY29sKHdpZHRoID0gMC41LCBmaWxsID0gc2NhbGVzOjpodWVfcGFsKCkoMSlbMV0pICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDE0LiBHbG9iYWwgY2FyYm9uIGluZXF1YWxpdHksIFxuMjAxOSBHcm91cCBjb250cmlidXRpb24gdG8gd29ybGQgZW1pc3Npb25zICglKSIsIAogICAgICAgeCA9ICIiLCB5ID0gIlNoYXJlIG9mIHdvcmxkIGVtaXNzaW9ucyAoJSkiKQpgYGAKCi0tLQoKIyMjIyBNZW1vCgoqIGB3aWR0aCA9IDAuNWA6IHdpZHRoIG9mIGJhcnMKKiBgZmlsbCA9IHNjYWxlczo6aHVlX3BhbCgpKDEpWzFdKWA6IGh1ZSBzY2FsZQogIC0gaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3NjYWxlX2h1ZS5odG1sLgoqIGBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKWA6IHBlcmNlbnQgZm9ybWF0CiAgLSBpZiBhY2N1cmFjeSA9IDAuMSwgd2UgaGF2ZSAxMC4wJSBldGMuCiogYGxhYnModGl0bGUgPSAiRmlndXJlIDE0LiBHbG9iYWwgY2FyYm9uIGluZXF1YWxpdHksIFxuMjAxOSBHcm91cCBjb250cmlidXRpb24gdG8gd29ybGQgZW1pc3Npb25zICglKSIsCiAgIHggPSAiIiwgeSA9ICJTaGFyZSBvZiB3b3JsZCBlbWlzc2lvbnMgKCUpIilgCiAgLSB0aXRsZSA9ICIiOiBgXG5gIGlzIGZvciBsaW5lIGZlZWQKICAtIHgsIHk6IGxhYmVscyBvZiB4LWF4aXMgYW5kIHktYXhpcwoKLS0tCgojIyMgRjEyOiBGZW1hbGUgc2hhcmUgaW4gZ2xvYmFsIGxhYm9yIGluY29tZXMsIDE5OTAtMjAyMAoKYGBge3IgZGF0YS1mMTIsIGNhc2ggPSBUUlVFfQpkZl9mMTIgPC0gcmVhZF9leGNlbCgiZGF0YS9XSVIyMDIycy54bHN4Iiwgc2hlZXQgPSAiZGF0YS1GMTIiKQpkZl9mMTIKYGBgCgotLS0KCmBgYHtyfQpkZl9mMTIgJT4lIAogIHNlbGVjdCh5ZWFyID0gIkRhdGEgbmVlZHMgdG8gYmUgdXBkYXRlZCIsIHZhbHVlID0gLi4uMikgJT4lCiAgZmlsdGVyKCFpcy5uYSh5ZWFyKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHZhbHVlKSkgKwogIGdlb21fY29sKHdpZHRoID0gMC41LCBmaWxsID0gc2NhbGVzOjpodWVfcGFsKCkoMilbMl0pCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjEyICU+JSAKICBzZWxlY3QoeWVhciA9ICJEYXRhIG5lZWRzIHRvIGJlIHVwZGF0ZWQiLCB2YWx1ZSA9IC4uLjIpICU+JQogIGZpbHRlcighaXMubmEoeWVhcikpICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSkpICsKICBnZW9tX2NvbCh3aWR0aCA9IDAuNSwgZmlsbCA9IHNjYWxlczo6aHVlX3BhbCgpKDIpWzJdKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC41LCBsaW5ldHlwZSA9IDIsIGNvbG91ciA9IHNjYWxlczo6aHVlX3BhbCgpKDIpWzFdKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDEyLiBGZW1hbGUgc2hhcmUgaW4gZ2xvYmFsIGxhYm9yIGluY29tZXMsIDE5OTAtMjAyMCIsIAogICAgICAgIHggPSAiIiwgeSA9ICIiKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNDgsIGxhYmVsID0gIkdlbmRlciBwYXJpdHkiLCBzaXplID0gMykgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDUuMiwgeSA9IDAuNDcsIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIldvbWVuIG1ha2Ugb25seSAzNSUgb2YgZ2xvYmFsIGxhYm9yIGluY29tZXMsIG1lbiBtYWtlIHRoZSByZW1haW5pbmcgIDY1JS4iLCB3aWR0aCA9IDQwKSwgc2l6ZSA9IDMpCmBgYAoKCiMjIyBGMTogR2xvYmFsIGluY29tZSBhbmQgd2VhbHRoIGluZXF1YWxpdHksIDIwMjEKCmBgYHtyIGRhdGEtZjEsIGNhc2ggPSBUUlVFfQpkZl9mMSA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUYxIikKZGZfZjEKYGBgCgotLS0KCmBgYHtyIGVjaG89RkFMU0V9CmRmX2YxX3JldiA8LSBkZl9mMSAlPiUgc2VsZWN0KGNhdCA9IC4uLjEsIDI6NCkgJT4lCiAgcGl2b3RfbG9uZ2VyKDI6NCwgbmFtZXNfdG8gPSAiZ3JvdXAiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQpkZl9mMV9yZXYKYGBgCgpgYGB7cn0KZGZfZjFfcmV2ICU+JQogIGdncGxvdChhZXMoeCA9IGNhdCwgeSA9IHZhbHVlLCBmaWxsID0gZ3JvdXApKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKQpgYGAKCi0tLQoKIyMjIFJlZmVyZW5jZXMgb2YgYGdncGxvdDJgCgoqIFRleHRib29rOiBbUiBmb3IgRGF0YSBTY2llbmNlLCBEYXRhIFZpc3VhbGl6YXRpb25dKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZGF0YS12aXN1YWxpc2F0aW9uLmh0bWwjZGF0YS12aXN1YWxpc2F0aW9uKQoKIyMjIyBSU3R1ZGlvIFByaW1lcnM6IFNlZSBSZWZlcmVuY2VzIGluIE1vb2RsZSBhdCB0aGUgYm90dG9tCgoqKlZpc3VhbGl6ZSBEYXRhKioKCiAgLSBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCiAgLSBCYXIgQ2hhcnRzCiAgLSBIaXN0b2dyYW1zCiAgLSBCb3hwbG90cyBhbmQgQ291bnRzCiAgLSBTY2F0dGVycGxvdHMKICAtIExpbmUgUGxvdHMKICAtIE92ZXJwbG90dGluZyBhbmQgQmlnIERhdGEKICAtIEN1c3RvbWl6ZSBZb3VyIFBsb3RzCgoKCiMjIFRoZSBXZWVrIEZvdXIgQXNzaWdubWVudCAoaW4gTW9vZGxlKQoKKipXREkgYW5kIGBnZ3Bsb3QyYCoqCgoqIENyZWF0ZSBhbiBSIE5vdGVib29rIG9mIGEgRGF0YSBBbmFseXNpcyBjb250YWluaW5nIHRoZSBmb2xsb3dpbmcgYW5kIHN1Ym1pdCB0aGUgcmVuZGVyZWQgSFRNTCBmaWxlIChlZy4gYGEzXzEyMzQ1Ni5uYi5odG1sYCAgYnkgcmVwbGFjaW5nIDEyMzQ1NiB3aXRoIHlvdXIgSUQpCiAgMS4gY3JlYXRlIGFuIFIgTm90ZWJvb2sgdXNpbmcgdGhlIFIgTm90ZWJvb2sgVGVtcGxhdGUgaW4gTW9vZGxlLCAgc2F2ZSBhcyBgYTNfMTIzNDU2LlJtZGAsIAogIDIuIHdyaXRlIHlvdXIgbmFtZSBhbmQgSUQgYW5kIHRoZSBjb250ZW50cywgCiAgMy4gcnVuIGVhY2ggY29kZSBibG9jaywgCiAgNC4gcHJldmlldyB0byBjcmVhdGUgYGEzXzEyMzQ1Ni5uYi5odG1sYCwKICA1LiBzdWJtaXQgIGBhM18xMjM0NTYubmIuaHRtbGAgdG8gTW9vZGxlLgoKMS4gQ2hvb3NlIGF0IGxlYXN0IG9uZSBpbmRpY2F0b3Igb2YgV0RJCgogICAgLSBJbmZvcm1hdGlvbiBvZiB0aGUgZGF0YTogTmFtZSwgSW5kaWNhdG9yLCBEZXNjcmlwdGlvbiwgU291cmNlLCBldGMuCiAgICAtIERvd25sb2FkIHRoZSBkYXRhIHdpdGggYFdESWAKICAgIC0gRXhwbGFpbiB3aHkgeW91IGNob3NlIHRoZSBpbmRpY2F0b3IKICAgIC0gTGlzdCBxdWVzdGlvbnMgeW91IHdhbnQgdG8gc3R1ZHkKCi0tLQoKMi4gRXhwbG9yZSB0aGUgZGF0YSB1c2luZyB2aXN1YWxpemF0aW9uIHVzaW5nIGBnZ3Bsb3QyYAoKICAgIC0gVXNlIGEgaGlzdG9ncmFtIChnZW9tX2hpc3RvZ3JhbSksIGJveHBsb3QgKGdlb21fYm94cGxvdCksIGEgc2NhdHRlciBwbG90IChnZW9tX3BvaW50KSwgYSBsaW5lIHBsb3QgKGdlb21fbGluZSkKICAgIC0gRm9yIGF0IGxlYXN0IG9uZSBjaGFydCwgYWRkIHRpdGxlLCBhbmQgbGFiZWxzIG9mIGF4aXMsIGFuZCBhZGQgYW4gZXhwbGFuYXRpb24gb2YgaXQKCjMuIE9ic2VydmF0aW9ucyBhbmQgZGlmZmljdWx0aWVzIGVuY291bnRlcmVkLgoKKipEdWU6KiogMjAyMy0wMS0xNiAyMzo1OTowMC4gU3VibWl0IHlvdXIgUiBOb3RlYm9vayBmaWxlIGluIE1vb2RsZSAoVGhlIFRoaXJkIEFzc2lnbm1lbnQpLiBEdWUgb24gTW9uZGF5IQoKIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpIElWICAKCiMjIFRpZHkgRGF0YQoKIyMjIFJldmlld3MgYW5kIFByZXZpZXdzCgojIyMgRXhhbXBsZTogV29ybGQgSW5lcXVpbGl0eSBSZXBvcnQgLSBXSVIyMDIyCgoqIFdvcmxkIEluZXF1YWxpdHkgUmVwb3J0OiBodHRwczovL3dpcjIwMjIud2lkLndvcmxkLwoqIEV4ZWN1dGl2ZSBTdW1tYXJ5OiBodHRwczovL3dpcjIwMjIud2lkLndvcmxkL2V4ZWN1dGl2ZS1zdW1tYXJ5LwoqIE1ldGhvZG9sb2d5OiBodHRwczovL3dpcjIwMjIud2lkLndvcmxkL21ldGhvZG9sb2d5LwoqIERhdGEgVVJMOiBodHRwczovL3dpcjIwMjIud2lkLndvcmxkL3d3dy1zaXRlL3VwbG9hZHMvMjAyMi8wMy9XSVIyMDIyVGFibGVzRmlndXJlcy1TdW1tYXJ5Lnhsc3gKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpCmBgYAoKYGBge3Igc3VtbWFyeS1kYXRhMiwgY2FzaCA9IFRSVUUsIGV2YWwgPSBGQUxTRX0KdXJsX3N1bW1hcnkgPC0gImh0dHBzOi8vd2lyMjAyMi53aWQud29ybGQvd3d3LXNpdGUvdXBsb2Fkcy8yMDIyLzAzL1dJUjIwMjJUYWJsZXNGaWd1cmVzLVN1bW1hcnkueGxzeCIKZG93bmxvYWQuZmlsZSh1cmwgPSB1cmxfc3VtbWFyeSwgZGVzdGZpbGUgPSAiZGF0YS9XSVIyMDIycy54bHN4IikgCmBgYAoKYGBge3J9CmV4Y2VsX3NoZWV0cygiZGF0YS9XSVIyMDIycy54bHN4IikKYGBgCgotLS0KCiMjIyBGMTogR2xvYmFsIGluY29tZSBhbmQgd2VhbHRoIGluZXF1YWxpdHksIDIwMjEKCmBgYHtyIGRhdGEtZjEtMiwgY2FzaCA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRX0KZGZfZjEgPC0gcmVhZF9leGNlbCgiZGF0YS9XSVIyMDIycy54bHN4Iiwgc2hlZXQgPSAiZGF0YS1GMSIpCmRmX2YxCmBgYAoKCgpgYGB7ciBlY2hvPUZBTFNFfQpkZl9mMV9yZXYgPC0gZGZfZjEgJT4lIHNlbGVjdChjYXQgPSAuLi4xLCAyOjQpICU+JQogIHBpdm90X2xvbmdlcigyOjQsIG5hbWVzX3RvID0gImdyb3VwIiwgdmFsdWVzX3RvID0gInZhbHVlIikKZGZfZjFfcmV2CmBgYAoKLS0tCgpgYGB7cn0KZGZfZjFfcmV2ICU+JQogIGdncGxvdChhZXMoeCA9IGNhdCwgeSA9IHZhbHVlLCBmaWxsID0gZ3JvdXApKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKQpgYGAKCi0tLQoKIyMjIFJlZmVyZW5jZXMgb2YgYHRpZHlyYAoKKiBUZXh0Ym9vazogW1IgZm9yIERhdGEgU2NpZW5jZSxUaWR5IERhdGFdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovdGlkeS1kYXRhLmh0bWwjdGlkeS1kYXRhKQoKIyMjIyBSU3R1ZGlvIFByaW1lcnM6IFNlZSBSZWZlcmVuY2VzIGluIE1vb2RsZSBhdCB0aGUgYm90dG9tCgoqKlRpZHkgWW91ciBEYXRhKioKCiAgLSBSZXNoYXBlIERhdGEKICAtIFNlcGFyYXRlIGFuZCBVbml0ZSBDb2x1bW5zCiAgLSBKb2luIERhdGEgU2V0cwogIAotLS0KCiMjIyBWYXJpYWJsZXMsIHZhbHVlcywgYW5kIG9ic2VydmF0aW9uczogRGVmaW5pdGlvbnMKCiogQSAqKnZhcmlhYmxlKiogaXMgYSBxdWFudGl0eSwgcXVhbGl0eSwgb3IgcHJvcGVydHkgdGhhdCB5b3UgY2FuIG1lYXN1cmUuCiogQSAqKnZhbHVlKiogaXMgdGhlIHN0YXRlIG9mIGEgdmFyaWFibGUgd2hlbiB5b3UgbWVhc3VyZSBpdC4gVGhlIHZhbHVlIG9mIGEgdmFyaWFibGUgbWF5IGNoYW5nZSBmcm9tIG1lYXN1cmVtZW50IHRvIG1lYXN1cmVtZW50LgoqIEFuICoqb2JzZXJ2YXRpb24qKiBvciAqKmNhc2UqKiBpcyBhIHNldCBvZiBtZWFzdXJlbWVudHMgbWFkZSB1bmRlciBzaW1pbGFyIGNvbmRpdGlvbnMgKHlvdSB1c3VhbGx5IG1ha2UgYWxsIG9mIHRoZSBtZWFzdXJlbWVudHMgaW4gYW4gb2JzZXJ2YXRpb24gYXQgdGhlIHNhbWUgdGltZSBhbmQgb24gdGhlIHNhbWUgb2JqZWN0KS4gQW4gb2JzZXJ2YXRpb24gd2lsbCBjb250YWluIHNldmVyYWwgdmFsdWVzLCBlYWNoIGFzc29jaWF0ZWQgd2l0aCBhIGRpZmZlcmVudCB2YXJpYWJsZS4gSeKAmWxsIHNvbWV0aW1lcyByZWZlciB0byBhbiBvYnNlcnZhdGlvbiBhcyBhIGNhc2Ugb3IgZGF0YSBwb2ludC4KKiAqKlRhYnVsYXIgZGF0YSoqIGlzIGEgdGFibGUgb2YgdmFsdWVzLCBlYWNoIGFzc29jaWF0ZWQgd2l0aCBhIHZhcmlhYmxlIGFuZCBhbiBvYnNlcnZhdGlvbi4gVGFidWxhciBkYXRhIGlzIHRpZHkgaWYgZWFjaCB2YWx1ZSBpcyBwbGFjZWQgaW4gaXRzIG93biBjZWxsLCBlYWNoIHZhcmlhYmxlIGluIGl0cyBvd24gY29sdW1uLCBhbmQgZWFjaCBvYnNlcnZhdGlvbiBpbiBpdHMgb3duIHJvdy4KKiBTbyBmYXIsIGFsbCBvZiB0aGUgZGF0YSB0aGF0IHlvdeKAmXZlIHNlZW4gaGFzIGJlZW4gdGlkeS4gSW4gcmVhbC1saWZlLCBtb3N0IGRhdGEgaXNu4oCZdCB0aWR5LCBzbyB3ZeKAmWxsIGNvbWUgYmFjayB0byB0aGVzZSBpZGVhcyBhZ2FpbiBpbiBEYXRhIFdyYW5nbGluZy4KCi0tLQoKIyMjIFRpZHkgRGF0YQoKPiDigJxEYXRhIGNvbWVzIGluIG1hbnkgZm9ybWF0cywgYnV0IFIgcHJlZmVycyBqdXN0IG9uZTogdGlkeSBkYXRhLuKAnSDigJQgR2FycmV0dCBHcm9sZW11bmQKCkRhdGEgY2FuIGNvbWUgaW4gYSB2YXJpZXR5IG9mIGZvcm1hdHMsIGJ1dCBvbmUgZm9ybWF0IGlzIGVhc2llciB0byB1c2UgaW4gUiB0aGFuIHRoZSBvdGhlcnMuIFRoaXMgZm9ybWF0IGlzIGtub3duIGFzIHRpZHkgZGF0YS4gQSBkYXRhIHNldCBpcyB0aWR5IGlmOgoKMS4gRWFjaCB2YXJpYWJsZSBpcyBpbiBpdHMgb3duIGNvbHVtbgoyLiBFYWNoIG9ic2VydmF0aW9uIGlzIGluIGl0cyBvd24gcm93CjMuIEVhY2ggdmFsdWUgaXMgaW4gaXRzIG93biBjZWxsICh0aGlzIGZvbGxvd3MgZnJvbSAjMSBhbmQgIzIpCgo+IOKAnFRpZHkgZGF0YSBzZXRzIGFyZSBhbGwgYWxpa2U7IGJ1dCBldmVyeSBtZXNzeSBkYXRhIHNldCBpcyBtZXNzeSBpbiBpdHMgb3duIHdheS7igJ0g4oCUIEhhZGxleSBXaWNraGFtCgo+IOKAnGFsbCBoYXBweSBmYW1pbGllcyBhcmUgYWxsIGFsaWtlOyBlYWNoIHVuaGFwcHkgZmFtaWx5IGlzIHVuaGFwcHkgaW4gaXRzIG93biB3YXnigJ0gLSBUb2xzdG95J3MgQW5uYSBLYXJlbmluYQoKLS0tCgojIyMgYHRpZHlyYCBCYXNpY3MKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjEwMCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZGF0YS90aWR5LTEucG5nIikKYGBgCgoxLiBFYWNoIHZhcmlhYmxlIGlzIGluIGl0cyBvd24gY29sdW1uCjIuIEVhY2ggb2JzZXJ2YXRpb24gaXMgaW4gaXRzIG93biByb3cKCi0tLQoKIyMjIFBpdm90IGRhdGEgZnJvbSB3aWRlIHRvIGxvbmc6IFtgcGl2b3RfbG9uZ2VyKClgXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3Bpdm90X2xvbmdlci5odG1sKQoKYGBgCnBpdm90X2xvbmdlcihkYXRhLCBjb2xzID0gPGNvbHVtbnMgdG8gcGl2b3QgaW50byBsb25nZXIgZm9ybWF0PiwKICBuYW1lc190byA9IDxuYW1lIG9mIHRoZSBuZXcgY2hhcmFjdGVyIGNvbHVtbj4sICMgZS5nLiAiZ3JvdXAiLCAiY2F0ZWdvcnkiLCAiY2xhc3MiCiAgdmFsdWVzX3RvID0gPG5hbWUgb2YgdGhlIGNvbHVtbiB0aGUgdmFsdWVzIG9mIGNlbGxzIGdvIHRvPikgIyBlLmcuICJ2YWx1ZSIsICJuIgpgYGAKCmBgYHtyfQpkZl9mMQpgYGAKCmBgYHtyfQooZGZfZjFfcmV2IDwtIGRmX2YxICU+JSBwaXZvdF9sb25nZXIoLTEsIG5hbWVzX3RvID0gImdyb3VwIiwgdmFsdWVzX3RvID0gInZhbHVlIikpCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjFfcmV2ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSAuLi4xLCB5ID0gdmFsdWUsIGZpbGwgPSBncm91cCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpCmBgYAoKLS0tCgpgYGB7ciBldmFsPUZBTFNFfQpkZl9mMV9yZXYgJT4lIGZpbHRlcihncm91cCAhPSAiVG9wIDElIikgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fY29sKGFlcyh4ID0gLi4uMSwgeSA9IHZhbHVlLCBmaWxsID0gZ3JvdXApLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBnZW9tX3RleHQoYWVzKHggPSAuLi4xLCB5ID0gdmFsdWUsIGdyb3VwID0gZ3JvdXAsIAogICAgICAgICAgICBsYWJlbCA9IHNjYWxlczo6bGFiZWxfcGVyY2VudChhY2N1cmFjeT0xKSh2YWx1ZSkpLCAKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSkpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDEuIEdsb2JhbCBpbmNvbWUgYW5kIHdlYWx0aCBpbmVxdWFsaXR5LCAyMDIxIiwKICAgICAgIHggPSAiIiwgeSA9ICJTaGFyZSBvZiB0b3RhbCBpbmNvbWUgb3Igd2VhbHRoIiwgZmlsbCA9ICIiKQpgYGAKCi0tLQoKYGBge3IgZWNobz1GQUxTRX0KZGZfZjFfcmV2ICU+JSBmaWx0ZXIoZ3JvdXAgIT0gIlRvcCAxJSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2NvbChhZXMoeCA9IC4uLjEsIHkgPSB2YWx1ZSwgZmlsbCA9IGdyb3VwKSwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gLi4uMSwgeSA9IHZhbHVlLCBncm91cCA9IGdyb3VwLCAKICAgICAgICAgICAgbGFiZWwgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoYWNjdXJhY3k9MSkodmFsdWUpKSwgCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSAxLiBHbG9iYWwgaW5jb21lIGFuZCB3ZWFsdGggaW5lcXVhbGl0eSwgMjAyMSIsCiAgICAgICB4ID0gIiIsIHkgPSAiU2hhcmUgb2YgdG90YWwgaW5jb21lIG9yIHdlYWx0aCIsIGZpbGwgPSAiIikKYGBgCioqSW50ZXJwcmV0YXRpb24qKjogVGhlIGdsb2JhbCBib3R0b20gNTAlIGNhcHR1cmVzIDguNSUgb2YgdG90YWwgaW5jb21lIG1lYXN1cmVkIGF0IFB1cmNoYXNpbmcgUG93ZXIgUGFyaXR5IChQUFApLiBUaGUgZ2xvYmFsIGJvdHRvbSA1MCUgb3ducyAyJSBvZiB3ZWFsdGggKGF0IFB1cmNoYXNpbmcgUG93ZXIgUGFyaXR5KS4gVGhlIGdsb2JhbCB0b3AgMTAlIG93bnMgNzYlIG9mIHRvdGFsIEhvdXNlaG9sZCB3ZWFsdGggYW5kIGNhcHR1cmVzIDUyJSBvZiB0b3RhbCBpbmNvbWUgaW4gMjAyMS4gTm90ZSB0aGF0IHRvcCB3ZWFsdGggaG9sZGVycyBhcmUgbm90IG5lY2Vzc2FyaWx5IHRvcCBpbmNvbWUgaG9sZGVycy4gSW5jb21lcyBhcmUgbWVhc3VyZWQgYWZ0ZXIgdGhlIG9wZXJhdGlvbiBvZiBwZW5zaW9uIGFuZCB1bmVtcGxveW1lbnQgc3lzdGVtcyBhbmQgYmVmb3JlIHRheGVzIGFuZCB0cmFuc2ZlcnMuICAKKipTb3VyY2VzIGFuZCBzZXJpZXMqKjogd2lyMjAyMi53aWQud29ybGQvbWV0aG9kb2xvZ3kuCgotLS0KCiMjIyBGMjogVGhlIHBvb3Jlc3QgaGFsZiBsYWdzIGJlaGluZDogQm90dG9tIDUwJSwgbWlkZGxlIDQwJSBhbmQgdG9wIDEwJSBpbmNvbWUgc2hhcmVzIGFjcm9zcyB0aGUgd29ybGQgaW4gMjAyMQoKYGBge3J9CmRmX2YyIDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjIiKQpkZl9mMgpgYGAKCi0tLQoKYGBge3J9CmRmX2YyICU+JSBwaXZvdF9sb25nZXIoY29scyA9IDM6NSwgbmFtZXNfdG8gPSAiZ3JvdXAiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQpgYGAKCi0tLQoKYGBge3J9CmRmX2YyICU+JSBwaXZvdF9sb25nZXIoY29scyA9IDM6NSwgbmFtZXNfdG8gPSAiZ3JvdXAiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBpc28sIHkgPSB2YWx1ZSwgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikKYGBgCgotLS0KCiMjIyBQaXZvdCBkYXRhIGZyb20gbG9uZyB0byB3aWRlOiAKW2BwaXZvdF93aWRlcigpYF0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9waXZvdF93aWRlci5odG1sKQpJbiBDb25zb2xlOiB2aWduZXR0ZSgicGl2b3QiKSAKCmBgYApwaXZvdF93aWRlcihkYXRhLCAKICBuYW1lc19mcm9tID0gPG5hbWUgb2YgdGhlIGNvbHVtbiAob3IgY29sdW1ucykgdG8gZ2V0IHRoZSBuYW1lIG9mIHRoZSBvdXRwdXQgY29sdW1uPiwKICB2YWx1ZXNfZnJvbSA9IDxuYW1lIG9mIHRoZSBjb2x1bW4gdG8gZ2V0IHRoZSB2YWx1ZSBvZiB0aGUgb3V0cHV0PikgCmBgYAoKCi0tLQoKYGBge3IgZWNobyA9IEZBTFNFfQpkZl9mMiAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSAzOjUsIG5hbWVzX3RvID0gImdyb3VwIiwgdmFsdWVzX3RvID0gInZhbHVlIikKYGBgCgpgYGAKcGl2b3Rfd2lkZXIoZGF0YSwgbmFtZXNfZnJvbSA9IGdyb3VwLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAKYGBgCgotLS0KCiMjIyBQcmFjdGljZTogRjQgYW5kIEYxMwoKRjQgYW5kIEYxMyBhcmUgc2ltaWxhci4gUGxlYXNlIHVzZSBgcGl2b3RfbG9uZ2VyYCB0byB0aWR5IHRoZSBkYXRhIGFuZCBjcmVhdGUgY2hhcnRzLgoKKiAqKlJlZmVyZW5jZXMqKjogaHR0cHM6Ly9kcy1zbC5naXRodWIuaW8vZGF0YS1hbmFseXNpcy93aXIyMDIyLm5iLmh0bWwKCiMjIyMgRG9uZSBMYXN0IFdlZWsKCiogRjEyOiBGZW1hbGUgc2hhcmUgaW4gZ2xvYmFsIGxhYm9yIGluY29tZXMsIDE5OTAtMjAyMAoqIEYxNDogR2xvYmFsIGNhcmJvbiBpbmVxdWFsaXR5LCAyMDE5LiBHcm91cCBjb250cmlidXRpb24gdG8gd29ybGQgZW1pc3Npb25zICglKQoKLS0tCgojIyMgRjM6IFRvcCAxMC9Cb3R0b20gNTAgaW5jb21lIGdhcHMgYWNyb3NzIHRoZSB3b3JsZCwgMjAyMQoKCmBgYHtyfQpkZl9mMyA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUYzIikKZGZfZjMKYGBgCgotLS0KCiMjIyBGMzogVG9wIDEwL0JvdHRvbSA1MCBpbmNvbWUgZ2FwcyBhY3Jvc3MgdGhlIHdvcmxkLCAyMDIxIC0gT3JpZ2luYWwKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjEwMCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZGF0YS9GMy5wbmciKQpgYGAKCi0tLQoKKiBUbyAxMCAvIEJvdHRvbSA1MCByYXRpbyBoYXMgNSBjbGFzc2VzOiA1LTEyLCAxMi0xMywgMTMtMTYsIDE2LTE5LCAxOS0xNDAKCmBgYHtyfQpkZl9mMyRUMTBCNTAgJT4lIHN1bW1hcnkoKQpgYGAKCi0tLQoKYGBge3J9CmRmX2YzICU+JSBnZ3Bsb3QoKSArIGdlb21faGlzdG9ncmFtKGFlcyhUMTBCNTApKQpgYGAKCi0tLQoKYGBge3J9CmRmX2YzICU+JSBhcnJhbmdlKGRlc2MoVDEwQjUwKSkKYGBgCgotLS0KCmBgYHtyfQpkZl9mMyAlPiUgCiAgbXV0YXRlKGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCA9IGN1dChUMTBCNTAsYnJlYWtzID0gYyg1LCAxMiwgMTMsIDE2LCAxOSwxNDApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gRkFMU0UpKSAKYGBgCgotLS0KCmBgYHtyfQp3b3JsZF9tYXAgPC0gbWFwX2RhdGEoIndvcmxkIikKZGZfZjMgJT4lIG11dGF0ZShgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2AgPSBjdXQoVDEwQjUwLGJyZWFrcyA9IGMoNSwgMTIsIDEzLCAxNiwgMTksMTQwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlLmxvd2VzdCA9IEZBTFNFKSkgJT4lCiAgZ2dwbG90KGFlcyhtYXBfaWQgPSBDb3VudHJ5KSkgKyAKICBnZW9tX21hcChhZXMoZmlsbCA9IGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCksIG1hcCA9IHdvcmxkX21hcCkgKyAKICBleHBhbmRfbGltaXRzKHggPSB3b3JsZF9tYXAkbG9uZywgeSA9IHdvcmxkX21hcCRsYXQpCmBgYAoKLS0tCgpgYGB7cn0Kd29ybGRfbWFwX3dpciA8LSB3b3JsZF9tYXAKd29ybGRfbWFwX3dpciRyZWdpb25bCiAgd29ybGRfbWFwX3dpciRyZWdpb249PSJEZW1vY3JhdGljIFJlcHVibGljIG9mIHRoZSBDb25nbyJdPC0iRFIgQ29uZ28iCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iUmVwdWJsaWMgb2YgQ29uZ28iXTwtIkNvbmdvIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09Ikl2b3J5IENvYXN0Il08LSJDb3RlIGRJdm9pcmUiCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iVmlldG5hbSJdPC0iVmlldCBOYW0iCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iUnVzc2lhIl08LSJSdXNzaWFuIEZlZGVyYXRpb24iCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iU291dGggS29yZWEiXTwtIktvcmVhIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09IlVLIl08LSJVbml0ZWQgS2luZ2RvbSIKd29ybGRfbWFwX3dpciRyZWdpb25bd29ybGRfbWFwX3dpciRyZWdpb249PSJCcnVuZWkiXTwtIkJydW5laSBEYXJ1c3NhbGFtIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09Ikxhb3MiXTwtIkxhbyBQRFIiCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iQ290ZSBkSXZvaXJlIl08LSJDb3RlIGQnSXZvaXJlIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09IkNhcGUgVmVyZGUiXTwtICJDYWJvIFZlcmRlIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09IlN5cmlhIl08LSAiU3lyaWFuIEFyYWIgUmVwdWJsaWMiCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iVHJpbmlkYWQiXTwtICJUcmluaWRhZCBhbmQgVG9iYWdvIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09IlRvYmFnbyJdPC0gIlRyaW5pZGFkIGFuZCBUb2JhZ28iCmBgYAogIAotLS0KCmBgYHtyfQpkZl9mMyAlPiUgbXV0YXRlKGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCA9IAogICAgY3V0KFQxMEI1MCwgYnJlYWtzID0gYyg1LCAxMiwgMTMsIDE2LCAxOSwxNDApLCBpbmNsdWRlLmxvd2VzdCA9IEZBTFNFKSkgJT4lCiAgZ2dwbG90KGFlcyhtYXBfaWQgPSBDb3VudHJ5KSkgKyAKICBnZW9tX21hcChhZXMoZmlsbCA9IGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCksIAogICAgbWFwID0gd29ybGRfbWFwX3dpcikgKyAKICAgIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcF93aXIkbG9uZywgeSA9IHdvcmxkX21hcF93aXIkbGF0KQpgYGAKCgoKLS0tCgpgYGB7cn0KZGZfZjMgJT4lIG11dGF0ZShgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2AgPSAKICAgIGN1dChUMTBCNTAsYnJlYWtzID0gYyg1LCAxMiwgMTMsIDE2LCAxOSwxNDApLCBpbmNsdWRlLmxvd2VzdCA9IEZBTFNFKSkgJT4lCiAgZ2dwbG90KGFlcyhtYXBfaWQgPSBDb3VudHJ5KSkgKyBnZW9tX21hcChhZXMoZmlsbCA9IGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCksIAogICAgbWFwID0gd29ybGRfbWFwX3dpcikgKyBleHBhbmRfbGltaXRzKHggPSB3b3JsZF9tYXBfd2lyJGxvbmcsIHkgPSB3b3JsZF9tYXBfd2lyJGxhdCkgKyAKICBjb29yZF9tYXAoIm9ydGhvZ3JhcGhpYyIsIG9yaWVudGF0aW9uID0gYygyNSwgNjAsIDApKQpgYGAKCi0tLQoKYGBge3J9CmRmX2YzICU+JSBtdXRhdGUoYFRvcCAxMCBCb3R0b20gNTAgUmF0aW9gID0gCiAgY3V0KFQxMEI1MCxicmVha3MgPSBjKDUsIDEyLCAxMywgMTYsIDE5LDE0MCksIGluY2x1ZGUubG93ZXN0ID0gRkFMU0UpKSAlPiUKICBnZ3Bsb3QoYWVzKG1hcF9pZCA9IENvdW50cnkpKSArIGdlb21fbWFwKGFlcyhmaWxsID0gYFRvcCAxMCBCb3R0b20gNTAgUmF0aW9gKSwgCiAgICBtYXAgPSB3b3JsZF9tYXBfd2lyKSArIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcF93aXIkbG9uZywgeSA9IHdvcmxkX21hcF93aXIkbGF0KSArIAogIGNvb3JkX21hcCgib3J0aG9ncmFwaGljIiwgb3JpZW50YXRpb24gPSBjKDE1LCAtODAsIDApKQpgYGAKCi0tLQoKCmBgYHtyfQpkZl9mMyAlPiUgbXV0YXRlKGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCA9IAogIGN1dChUMTBCNTAsYnJlYWtzID0gYyg1LCAxMiwgMTMsIDE2LCAxOSwxNDApLCBpbmNsdWRlLmxvd2VzdCA9IEZBTFNFKSkgJT4lCiAgZ2dwbG90KGFlcyhtYXBfaWQgPSBDb3VudHJ5KSkgKyBnZW9tX21hcChhZXMoZmlsbCA9IGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCksIAogICAgbWFwID0gd29ybGRfbWFwX3dpcikgKyAKICBleHBhbmRfbGltaXRzKHggPSB3b3JsZF9tYXBfd2lyJGxvbmcsIHkgPSB3b3JsZF9tYXBfd2lyJGxhdCkKYGBgCgotLS0KCmBgYHtyIGV2YWwgPSBGQUxTRX0KZGZfZjMgJT4lIAogIG11dGF0ZShgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2AgPSAKICAgICAgICBjdXQoVDEwQjUwLGJyZWFrcyA9IGMoNSwgMTIsIDEzLCAxNiwgMTksMTQwKSwgaW5jbHVkZS5sb3dlc3QgPSBGQUxTRSkpICU+JQogIGdncGxvdChhZXMobWFwX2lkID0gQ291bnRyeSkpICsgCiAgZ2VvbV9tYXAoYWVzKGZpbGwgPSBgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2ApLCBtYXAgPSB3b3JsZF9tYXBfd2lyKSArIAogIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcF93aXIkbG9uZywgeSA9IHdvcmxkX21hcF93aXIkbGF0KSAgKyAKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSAzLiBUb3AgMTAvQm90dG9tIDUwIGluY29tZSBnYXBzIGFjcm9zcyB0aGUgd29ybGQsIDIwMjEiLAogICAgICAgeCA9ICIiLCB5ID0gIiIsIGZpbGwgPSAiVG9wIDEwL0JvdHRvbSA1MCByYXRpbyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0nWWxPclJkJykKYGBgCgotLS0KCmBgYHtyIGVjaG8gPSBGQUxTRX0KZGZfZjMgJT4lIAogIG11dGF0ZShgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2AgPSBjdXQoVDEwQjUwLGJyZWFrcyA9IGMoNSwgMTIsIDEzLCAxNiwgMTksMTQwKSwgaW5jbHVkZS5sb3dlc3QgPSBGQUxTRSkpICU+JQogIGdncGxvdChhZXMobWFwX2lkID0gQ291bnRyeSkpICsgZ2VvbV9tYXAoYWVzKGZpbGwgPSBgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2ApLCBtYXAgPSB3b3JsZF9tYXBfd2lyKSArIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcF93aXIkbG9uZywgeSA9IHdvcmxkX21hcF93aXIkbGF0KSAgKyAKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSAzLiBUb3AgMTAvQm90dG9tIDUwIGluY29tZSBnYXBzIGFjcm9zcyB0aGUgd29ybGQsIDIwMjEiLAogICAgICAgeCA9ICIiLCB5ID0gIiIsIGZpbGwgPSAiVG9wIDEwL0JvdHRvbSA1MCByYXRpbyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0nWWxPclJkJykKYGBgCgotLS0KCmBgYHtyfQpkZl9mMyAlPiUgYW50aV9qb2luKHdvcmxkX21hcF93aXIsIGJ5ID0gYygiQ291bnRyeSIgPSAicmVnaW9uIikpCmBgYAoKKipGaWx0ZXJpbmcgam9pbnMqKgoKKiBgYW50aV9qb2luKHgseSwgLi4uKWA6IHJldHVybiBhbGwgcm93cyBmcm9tIHggd2l0aG91dCBhIG1hdGNoIGluIHkuCiogYHNlbWlfam9pbih4LHksIC4uLilgOiByZXR1cm4gYWxsIHJvd3MgZnJvbSB4IHdpdGggYSBtYXRjaCBpbiB5LgoKQ2hlY2sgYGRwbHlyYCBjaGVhdCBzaGVldCwgYW5kIFBvc2l0IFByaW1lcnMgVGlkeSBEYXRhLgoKLS0tCgojIyMgUmVtYWluaW5nIENoYXJ0cwoKKiBGNTogR2xvYmFsIGluY29tZSBpbmVxdWFsaXR5OiBUMTAvQjUwIHJhdGlvLCAxODIwLTIwMjAgLSBmaXQgY3VydmUKKiBGOTogQXZlcmFnZSBhbm51YWwgd2VhbHRoIGdyb3d0aCByYXRlLCAxOTk1LTIwMjEgLSBmaXQgY3VydmUgKyBhbHBoYQoqIEY3OiBHbG9iYWwgaW5jb21lIGluZXF1YWxpdHksIDE4MjAtMjAyMCAtIHBpdm90ICsgZml0IGN1cnZlCiogRjEwOiBUaGUgc2hhcmUgb2Ygd2VhbHRoIG93bmVkIGJ5IHRoZSBnbG9iYWwgMC4xJSBhbmQgYmlsbGlvbmFpcmVzLCAyMDIxIC0gcGl2b3QgKyBmaXQgY3VydmUKCgoqIEY2OiBHbG9iYWwgaW5jb21lIGluZXF1YWxpdHk6IEJldHdlZW4gdnMuIFdpdGhpbiBjb3VudHJ5IGluZXF1YWxpdHkgKFRoZWlsIGluZGV4KSwgMTgyMC0yMDIwIC0gcGl2b3QgKyBhcmVhCgoqIEYxMTogVG9wIDElIHZzIGJvdHRvbSA1MCUgd2VhbHRoIHNoYXJlcyBpbiBXZXN0ZXJuIEV1cm9wZSBhbmQgdGhlIFVTLCAxOTEwLTIwMjAgLSBwaXZvdCBuYW1lX3NlcCArIGZpdCBjdXJ2ZQoqIEY4OiBUaGUgcmlzZSBvZiBwcml2YXRlIHZlcnN1cyB0aGUgZGVjbGluZSBvZiBwdWJsaWMgd2VhbHRoIGluIHJpY2ggY291bnRyaWVzLCAxOTcwLTIwMjAgLSByZW5hbWUgKyBwaXZvdCArIHBpdm90ICsgZml0IGN1cnZlCgoqIEYxNTogUGVyIGNhcGl0YSBlbWlzc2lvbnMgYWNyaXNzIHRoZSB3b3JsZCwgMjAxOSAtIGFkZCByb3cgbmFtZXMgKyBkb2RnZQoKCi0tLQoKIyMjIEY1OiBHbG9iYWwgaW5jb21lIGluZXF1YWxpdHk6IFQxMC9CNTAgcmF0aW8sIDE4MjAtMjAyMAoKYGBge3IgZGF0YS1mNSwgY2FzaCA9IFRSVUV9CihkZl9mNSA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUY1IikpCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjUgJT4lIGdncGxvdChhZXMoeCA9IHksIHkgPSB0MTBiNTApKSArIGdlb21fbGluZSgpICsgZ2VvbV9zbW9vdGgoc3Bhbj0wLjI1LCBzZT1GQUxTRSkKYGBgCgotLS0KCiMjIyBGOTogQXZlcmFnZSBhbm51YWwgd2VhbHRoIGdyb3d0aCByYXRlLCAxOTk1LTIwMjEgLSBmaXQgY3VydmUgKyBhbHBoYQoKYGBge3IgZGF0YS1mOSwgY2FzaCA9IFRSVUV9CmRmX2Y5IDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjkiKTsgZGZfZjkKYGBgCgotLS0KCmBgYHtyfQpkZl9mOSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcCwgeSA9IGBXZWFsdGggZ3Jvd3RoIDE5OTUtMjAyMWApKSArIGdlb21fc21vb3RoKHNwYW4gPSAwLjMwLCBzZSA9IEZBTFNFKQpgYGAKCi0tLQoKIyMjIEY3OiBHbG9iYWwgaW5jb21lIGluZXF1YWxpdHksIDE4MjAtMjAyMCAtIHBpdm90ICsgZml0IGN1cnZlCgpgYGB7ciBkYXRhLWY3LCBjYXNoID0gVFJVRX0KZGZfZjcgPC0gcmVhZF9leGNlbCgiZGF0YS9XSVIyMDIycy54bHN4Iiwgc2hlZXQgPSAiZGF0YS1GNyIpOyBkZl9mNwpgYGAKCi0tLQoKYGBge3J9CmRmX2Y3ICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IDI6NCwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIGdncGxvdChhZXMoeCA9IHksIHkgPSB2YWx1ZSwgY29sb3IgPSB0eXBlKSkgKwogIHN0YXRfc21vb3RoKGZvcm11bGEgPSB5fngsIG1ldGhvZCA9ICJsb2VzcyIsIHNwYW4gPSAwLjI1LCBzZSA9IEZBTFNFKQpgYGAKCi0tLQoKIyMjIEYxMDogVGhlIHNoYXJlIG9mIHdlYWx0aCBvd25lZCBieSB0aGUgZ2xvYmFsIDAuMSUgYW5kIGJpbGxpb25haXJlcywgMjAyMSAtIHBpdm90ICsgZml0IGN1cnZlCgpgYGB7ciBkYXRhLWYxMCwgY2FzaCA9IFRSVUV9CmRmX2YxMCA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUYxMCIpOyBkZl9mMTAKYGBgCgotLS0KCmBgYHtyfQpkZl9mMTAgJT4lIAogIHNlbGVjdCh5ZWFyLCAiR2xvYmFsIEJpbGxpb25haXJlIFdlYWx0aCIgPSBibl9oaHdlYWwsICJUb3AgMC4wMSUiID0gdG9wMC4xX2hod2VhbCkgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9ICJncm91cCIsIi52YWx1ZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjEwICU+JSAKICBzZWxlY3QoeWVhciwgIkdsb2JhbCBCaWxsaW9uYWlyZSBXZWFsdGgiID0gYm5faGh3ZWFsLCAiVG9wIDAuMDElIiA9IHRvcDAuMV9oaHdlYWwpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSAiZ3JvdXAiLCIudmFsdWUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBnZ3Bsb3QoKSArCiAgc3RhdF9zbW9vdGgoYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUsIGNvbG9yID0gZ3JvdXApLCBmb3JtdWxhID0geX54LCBtZXRob2QgPSAibG9lc3MiLCBzcGFuID0gMC4yNSwgc2UgPSBGQUxTRSkKYGBgCgotLS0KCiMjIyBGNjogR2xvYmFsIGluY29tZSBpbmVxdWFsaXR5OiBCZXR3ZWVuIHZzLiBXaXRoaW4gY291bnRyeSBpbmVxdWFsaXR5IChUaGVpbCBpbmRleCksIDE4MjAtMjAyMCAtIHBpdm90ICsgYXJlYQoKYGBge3IgZGF0YS1mNiwgY2FzaCA9IFRSVUV9CmRmX2Y2IDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjYiKTsgZGZfZjYKYGBgCgotLS0KCmBgYHtyIGV2YWwgPUZBTFNFfQpkZl9mNiAlPiUgc2VsZWN0KHllYXIgPSAiLi4uMSIsIDI6MykgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjMsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUodHlwZXMgPSBmYWN0b3IodHlwZSwgCiAgICAgIGxldmVscyA9IGMoIldpdGhpbi1jb3VudHJ5IGluZXF1YWxpdHkiLCAiQmV0d2Vlbi1jb3VudHJ5IGluZXF1YWxpdHkiKSkpICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSwgZmlsbCA9IHR5cGVzKSkgKwogIGdlb21fYXJlYSgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHJvdW5kKHNlcSgxODIwLCAyMDIwLCBieSA9IDIwKSwxKSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cmV2KHNjYWxlczo6aHVlX3BhbCgpKDIpKSwgCiAgICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHN0cl93cmFwKHgsIHdpZHRoID0gMTUpKSArCiAgbGFicyh0aXRsZSA9ICJGaWd1cmUgNi4gR2xvYmFsIGluY29tZSBpbmVxdWFsaXR5OiAKICAgICAgIFxuQmV0d2VlbiB2cy4gd2l0aGluIGNvdW50cnkgaW5lcXVhbGl0eSAoVGhlaWwgaW5kZXgpLCAxODIwLTIwMjAiLAogICAgICAgeCA9ICIiLCB5ID0gIlNoYXJlIG9mIGdsb2JhbCBpbmVxdWFsaXR5ICglIG9mIHRvdGFsIFRoZWlsIGluZGV4KSIsIGZpbGwgPSAiIikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxODUwLCB5ID0gMC4yOCwgCiAgICAgIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIjE4MjA6IEJldHdlZW4gY291bnRyeSBpbmVxdWFsaXR5IHJlcHJlc2VudHMgMTElIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mIGdsb2JhbCBpbmVxdWFsaXR5Iiwgd2lkdGggPSAyMCksIHNpemUgPSAzKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDE5ODAsIHkgPSAwLjcwLCAKICAgICAgbGFiZWwgPSBzdHJpbmdyOjpzdHJfd3JhcCgiMTk4MDogQmV0d2VlbiBjb3VudHJ5IGluZXF1YWxpdHkgcmVwcmVzZW50cyA1NyUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2YgZ2xvYmFsIGluZXF1YWxpdHkiLCB3aWR0aCA9IDIwKSwgc2l6ZSA9IDMpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxOTkwLCB5ID0gMC4zMCwgCiAgICAgIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIjIwMjA6IEJldHdlZW4gY291bnRyeSBpbmVxdWFsaXR5IHJlcHJlc2VudHMgMzIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mIGdsb2JhbCBpbmVxdWFsaXR5Iiwgd2lkdGggPSAyMCksIHNpemUgPSAzKQpgYGAKCi0tLQoKCmBgYHtyIGVjaG8gPUZBTFNFfQpkZl9mNiAlPiUgc2VsZWN0KHllYXIgPSAiLi4uMSIsIDI6MykgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjMsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUodHlwZXMgPSBmYWN0b3IodHlwZSwgCiAgICAgIGxldmVscyA9IGMoIldpdGhpbi1jb3VudHJ5IGluZXF1YWxpdHkiLCAiQmV0d2Vlbi1jb3VudHJ5IGluZXF1YWxpdHkiKSkpICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSwgZmlsbCA9IHR5cGVzKSkgKwogIGdlb21fYXJlYSgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHJvdW5kKHNlcSgxODIwLCAyMDIwLCBieSA9IDIwKSwxKSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cmV2KHNjYWxlczo6aHVlX3BhbCgpKDIpKSwgCiAgICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHN0cl93cmFwKHgsIHdpZHRoID0gMTUpKSArCiAgbGFicyh0aXRsZSA9ICJGaWd1cmUgNi4gR2xvYmFsIGluY29tZSBpbmVxdWFsaXR5OiAKICAgICAgIFxuQmV0d2VlbiB2cy4gd2l0aGluIGNvdW50cnkgaW5lcXVhbGl0eSAoVGhlaWwgaW5kZXgpLCAxODIwLTIwMjAiLAogICAgICAgeCA9ICIiLCB5ID0gIlNoYXJlIG9mIGdsb2JhbCBpbmVxdWFsaXR5ICglIG9mIHRvdGFsIFRoZWlsIGluZGV4KSIsIGZpbGwgPSAiIikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxODUwLCB5ID0gMC4yOCwgCiAgICAgIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIjE4MjA6IEJldHdlZW4gY291bnRyeSBpbmVxdWFsaXR5IHJlcHJlc2VudHMgMTElIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mIGdsb2JhbCBpbmVxdWFsaXR5Iiwgd2lkdGggPSAyMCksIHNpemUgPSAzKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDE5ODAsIHkgPSAwLjcwLCAKICAgICAgbGFiZWwgPSBzdHJpbmdyOjpzdHJfd3JhcCgiMTk4MDogQmV0d2VlbiBjb3VudHJ5IGluZXF1YWxpdHkgcmVwcmVzZW50cyA1NyUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2YgZ2xvYmFsIGluZXF1YWxpdHkiLCB3aWR0aCA9IDIwKSwgc2l6ZSA9IDMpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxOTkwLCB5ID0gMC4zMCwgCiAgICAgIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIjIwMjA6IEJldHdlZW4gY291bnRyeSBpbmVxdWFsaXR5IHJlcHJlc2VudHMgMzIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mIGdsb2JhbCBpbmVxdWFsaXR5Iiwgd2lkdGggPSAyMCksIHNpemUgPSAzKQpgYGAKCgotLS0KCiMjIyBGMTE6IFRvcCAxJSB2cyBib3R0b20gNTAlIHdlYWx0aCBzaGFyZXMgaW4gV2VzdGVybiBFdXJvcGUgYW5kIHRoZSBVUywgMTkxMC0yMDIwIC0gcGl2b3QgbmFtZV9zZXAgKyBmaXQgY3VydmUKCmBgYHtyIGRhdGEtZjExLCBjYXNoID0gVFJVRX0KZGZfZjExIDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjExIik7IGRmX2YxMQpgYGAKCi0tLQoKYGBge3IgZXZhbCA9IEZBTFNFfQpkZl9mMTEgJT4lIAogIHJlbmFtZSgheWVhciwgVVNfYm90NTAgPSBVU2JvdDUwLCBVU190b3AxID0gVVN0b3AxLCAKICAgICAgICAgRVVfYm90NTAgPSBFVWJvdDUwLCBFVV90b3AxID0gRVV0b3AxKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiZ3JvdXAiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAlPiUKICBwaXZvdF9sb25nZXIoMzo0LCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgZ2dwbG90KCkgKwogIHN0YXRfc21vb3RoKGFlcyh4ID0geWVhciwgeSA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBsaW5ldHlwZSA9IHR5cGUpLCAKICAgICAgICAgICAgICBzcGFuID0gMC4yNSwgc2UgPSBGQUxTRSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSByb3VuZChzZXEoMTkxMCwgMjAyMCwgYnkgPSAxMCksMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgbGFicyh0aXRsZSA9ICJGaWd1cmUgMTEuIFRvcCAxJSB2cyBib3R0b20gNTAlIHdlYWx0aCBzaGFyZXMgCiAgICAgICBcbiBpbiBXZXN0ZXJuIEV1cm9wZSBhbmQgdGhlIFVTLCAxOTEwLTIwMjAiLCAKICAgICAgIHggPSAiIiwgeSA9ICJTaGFyZSBvZiB0b3RhbCBwZXJzb25hbCB3ZWFsdGggKCUpIiwgY29sb3IgPSAiIiwgbGluZXR5cGUgPSAiIikgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJkb3R0ZWQiLCJzb2xpZCIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjAwMCwgeSA9IDAuNTAsIAogICAgICBsYWJlbCA9IHN0cmluZ3I6OnN0cl93cmFwKCJXZWFsdGggaW5lcXVhbGl0eSBoYXMgYmVlbiByaXNpbmcgYXQgCiAgICAgICAgZGlmZmVyZW50IHNwZWVkcyBhZnRlciBhIGhpc3RvcmljYWwgZGVjbGluZS4gVGhlIGJvdHRvbSA1MCUgaGFzIGFsd2F5cyBiZWVuIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJlbWVseSBsb3cuIiwgd2lkdGggPSAzMCksIHNpemUgPSAzKQpgYGAKCgotLS0KCiMjIyMgU3RlcCAxLgoKYGBge3J9CmRmX2YxMSAlPiUgcmVuYW1lKCF5ZWFyLCBVU19ib3Q1MCA9IFVTYm90NTAsIFVTX3RvcDEgPSBVU3RvcDEsIAogICAgICAgICAgICAgICAgICBFVV9ib3Q1MCA9IEVVYm90NTAsIEVVX3RvcDEgPSBFVXRvcDEpIApgYGAKCi0tLQoKIyMjIyBTdGVwIDIuIAoKYGBge3Igd2FybmluZyA9IEZBTFNFLCBldmFsPUZBTFNFfQpkZl9mMTEgJT4lIAogIHJlbmFtZSgheWVhciwgVVNfYm90NTAgPSBVU2JvdDUwLCBVU190b3AxID0gVVN0b3AxLCAKICAgICAgICAgRVVfYm90NTAgPSBFVWJvdDUwLCBFVV90b3AxID0gRVV0b3AxKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiZ3JvdXAiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKQpgYGAKCi0tLQoKIyMjIyBTdGVwIDIuIAoKYGBge3Igd2FybmluZyA9IEZBTFNFLCBlY2hvPUZBTFNFfQpkZl9mMTEgJT4lIAogIHJlbmFtZSgheWVhciwgVVNfYm90NTAgPSBVU2JvdDUwLCBVU190b3AxID0gVVN0b3AxLCBFVV9ib3Q1MCA9IEVVYm90NTAsIEVVX3RvcDEgPSBFVXRvcDEpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSBjKCJncm91cCIsIi52YWx1ZSIpLCBuYW1lc19zZXAgPSAiXyIpCmBgYAoKLS0tCgojIyMjIFN0ZXAgMy4KCmBgYHtyIHdhcm5pbmcgPSBGQUxTRSwgZXZhbD1GQUxTRX0KZGZfZjExICU+JSAKICByZW5hbWUoIXllYXIsIFVTX2JvdDUwID0gVVNib3Q1MCwgVVNfdG9wMSA9IFVTdG9wMSwgCiAgICAgICAgIEVVX2JvdDUwID0gRVVib3Q1MCwgRVVfdG9wMSA9IEVVdG9wMSkgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImdyb3VwIiwiLnZhbHVlIiksIAogICAgICAgICAgICAgICBuYW1lc19zZXAgPSAiXyIpICU+JQogIHBpdm90X2xvbmdlcigzOjQsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAKYGBgCgotLS0KCiMjIyMgU3RlcCAzLgoKYGBge3Igd2FybmluZyA9IEZBTFNFLCBlY2hvPUZBTFNFfQpkZl9mMTEgJT4lIAogIHJlbmFtZSgheWVhciwgVVNfYm90NTAgPSBVU2JvdDUwLCBVU190b3AxID0gVVN0b3AxLCBFVV9ib3Q1MCA9IEVVYm90NTAsIEVVX3RvcDEgPSBFVXRvcDEpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSBjKCJncm91cCIsIi52YWx1ZSIpLCBuYW1lc19zZXAgPSAiXyIpICU+JQogIHBpdm90X2xvbmdlcigzOjQsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAKYGBgCgotLS0KCmBgYHtyIHdhcm5pbmcgPSBGQUxTRSwgZWNobz1GQUxTRX0KZGZfZjExICU+JSAKICByZW5hbWUoIXllYXIsIFVTX2JvdDUwID0gVVNib3Q1MCwgVVNfdG9wMSA9IFVTdG9wMSwgRVVfYm90NTAgPSBFVWJvdDUwLCBFVV90b3AxID0gRVV0b3AxKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiZ3JvdXAiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAlPiUKICBwaXZvdF9sb25nZXIoMzo0LCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgZ2dwbG90KCkgKwogIHN0YXRfc21vb3RoKGFlcyh4ID0geWVhciwgeSA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBsaW5ldHlwZSA9IHR5cGUpLCBmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsb2VzcyIsIHNwYW4gPSAwLjI1LCBzZSA9IEZBTFNFKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHJvdW5kKHNlcSgxOTEwLCAyMDIwLCBieSA9IDEwKSwxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSAxMS4gVG9wIDElIHZzIGJvdHRvbSA1MCUgd2VhbHRoIHNoYXJlcyBcbiBpbiBXZXN0ZXJuIEV1cm9wZSBhbmQgdGhlIFVTLCAxOTEwLTIwMjAiLCAKICAgICAgIHggPSAiIiwgeSA9ICJTaGFyZSBvZiB0b3RhbCBwZXJzb25hbCB3ZWFsdGggKCUpIiwgY29sb3IgPSAiIiwgbGluZXR5cGUgPSAiIikgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJkb3R0ZWQiLCJzb2xpZCIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjAwMCwgeSA9IDAuNTAsIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIldlYWx0aCBpbmVxdWFsaXR5IGhhcyBiZWVuIHJpc2luZyBhdCBkaWZmZXJlbnQgc3BlZWRzIGFmdGVyIGEgaGlzdG9yaWNhbCBkZWNsaW5lLiBUaGUgYm90dG9tIDUwJSBoYXMgYWx3YXlzIGJlZW4gZXh0cmVtZWx5IGxvdy4iLCB3aWR0aCA9IDMwKSwgc2l6ZSA9IDMpCmBgYAoKLS0tCgojIyMgRjg6IFRoZSByaXNlIG9mIHByaXZhdGUgdmVyc3VzIHRoZSBkZWNsaW5lIG9mIHB1YmxpYyB3ZWFsdGggaW4gcmljaCBjb3VudHJpZXMsIDE5NzAtMjAyMCAtIHJlbmFtZSArIHBpdm90ICsgcGl2b3QgKyBmaXQgY3VydmUKCmBgYHtyIGRhdGEtZjgsIGNhc2ggPSBUUlVFfQpkZl9mOCA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUY4Iik7IGRmX2Y4CmBgYAoKLS0tCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBldmFsID0gRkFMU0V9CmRmX2Y4ICU+JSAKICBzZWxlY3QoeWVhciwgR2VybWFueV9wdWJsaWMgPSBHZXJtYW55LCBHZXJtYW55X3ByaXZhdGUgPSAnR2VybWFueSAocHJpdmF0ZSknLCAKICAgICAgICAgU3BhaW5fcHVibGljID0gU3BhaW4sIFNwYWluX3ByaXZhdGUgPSAnU3BhaW4gKHByaXZhdGUpJywgCiAgICAgICAgIEZyYW5jZV9wdWJsaWMgPSBGcmFuY2UsIEZyYW5jZV9wcml2YXRlID0gJ0ZyYW5jZSAocHJpdmF0ZSknLCAKICAgICAgICAgVUtfcHVibGljICA9IFVLLCBVS19wcml2YXRlID0gJ1VLIChwcml2YXRlKScsIAogICAgICAgICBKYXBhbl9wdWJsaWMgPSBKYXBhbiwgSmFwYW5fcHJpdmF0ZSA9ICdKYXBhbiAocHJpdmF0ZSknLCAKICAgICAgICAgTm9yd2F5X3B1YmxpYyA9IE5vcndheSwgTm9yd2F5X3ByaXZhdGUgPSAnTm9yd2F5IChwcml2YXRlKScsCiAgICAgICAgIFVTQV9wdWJsaWMgPSBVU0EsIFVTQV9wcml2YXRlID0gJ1VTQSAocHJpdmF0ZSknKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiY291bnRyeSIsIi52YWx1ZSIpLCBuYW1lc19zZXAgPSAiXyIpICU+JQogIHBpdm90X2xvbmdlcigzOjQsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBnZ3Bsb3QoKSArCiAgc3RhdF9zbW9vdGgoYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUsIGNvbG9yID0gY291bnRyeSwgbGluZXR5cGUgPSB0eXBlKSwgCiAgICAgICAgICAgICAgc3BhbiA9IDAuMjUsIHNlID0gRkFMU0UsIHNpemU9MC43NSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSA4LiBUaGUgcmlzZSBvZiBwcml2YXRlIHZlcnN1cyB0aGUgZGVjbGluZSBvZiBwdWJsaWMgCiAgICAgICB3ZWFsdGggaW4gcmljaCBjb3VudHJpZXMsIDE5NzAtMjAyMCIsIAogICAgICAgeCA9ICIiLCB5ID0gIndlYWx0aCBhcyBhcyAlIG9mIG5hdGlvbmFsIGluY29tZSIsIGNvbG9yID0gIiIsIHR5cGUgPSAiIikKYGBgCgotLS0KCiMjIyMgU3RlcCAxCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgCmBgYAoKCi0tLQoKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9CmRmX2Y4ICU+JSAKICBzZWxlY3QoeWVhciwgR2VybWFueV9wdWJsaWMgPSBHZXJtYW55LCBHZXJtYW55X3ByaXZhdGUgPSAnR2VybWFueSAocHJpdmF0ZSknLCAKICAgICAgICAgU3BhaW5fcHVibGljID0gU3BhaW4sIFNwYWluX3ByaXZhdGUgPSAnU3BhaW4gKHByaXZhdGUpJywgCiAgICAgICAgIEZyYW5jZV9wdWJsaWMgPSBGcmFuY2UsIEZyYW5jZV9wcml2YXRlID0gJ0ZyYW5jZSAocHJpdmF0ZSknLCAKICAgICAgICAgVUtfcHVibGljICA9IFVLLCBVS19wcml2YXRlID0gJ1VLIChwcml2YXRlKScsIAogICAgICAgICBKYXBhbl9wdWJsaWMgPSBKYXBhbiwgSmFwYW5fcHJpdmF0ZSA9ICdKYXBhbiAocHJpdmF0ZSknLCAKICAgICAgICAgTm9yd2F5X3B1YmxpYyA9IE5vcndheSwgTm9yd2F5X3ByaXZhdGUgPSAnTm9yd2F5IChwcml2YXRlKScsCiAgICAgICAgIFVTQV9wdWJsaWMgPSBVU0EsIFVTQV9wcml2YXRlID0gJ1VTQSAocHJpdmF0ZSknKQpgYGAKCgoKCi0tLQoKIyMjIyBTdGVwIDIuCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImNvdW50cnkiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAKYGBgCgoKLS0tCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImNvdW50cnkiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKQpgYGAKCi0tLQoKIyMjIyBTdGVwIDMuCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImNvdW50cnkiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAlPiUKICBwaXZvdF9sb25nZXIoMzo0LCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInZhbHVlIikKYGBgCgotLS0KCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImNvdW50cnkiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAlPiUKICBwaXZvdF9sb25nZXIoMzo0LCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgCmBgYAoKLS0tCgojIyMjIFN0ZXAgMy4gRmluYWwgU3RlcAoKYGBge3IgZXZhbD1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGZfZjggJT4lIAogIHNlbGVjdCh5ZWFyLCBHZXJtYW55X3B1YmxpYyA9IEdlcm1hbnksIEdlcm1hbnlfcHJpdmF0ZSA9ICdHZXJtYW55IChwcml2YXRlKScsIAogICAgICAgICBTcGFpbl9wdWJsaWMgPSBTcGFpbiwgU3BhaW5fcHJpdmF0ZSA9ICdTcGFpbiAocHJpdmF0ZSknLCAKICAgICAgICAgRnJhbmNlX3B1YmxpYyA9IEZyYW5jZSwgRnJhbmNlX3ByaXZhdGUgPSAnRnJhbmNlIChwcml2YXRlKScsIAogICAgICAgICBVS19wdWJsaWMgID0gVUssIFVLX3ByaXZhdGUgPSAnVUsgKHByaXZhdGUpJywgCiAgICAgICAgIEphcGFuX3B1YmxpYyA9IEphcGFuLCBKYXBhbl9wcml2YXRlID0gJ0phcGFuIChwcml2YXRlKScsIAogICAgICAgICBOb3J3YXlfcHVibGljID0gTm9yd2F5LCBOb3J3YXlfcHJpdmF0ZSA9ICdOb3J3YXkgKHByaXZhdGUpJywKICAgICAgICAgVVNBX3B1YmxpYyA9IFVTQSwgVVNBX3ByaXZhdGUgPSAnVVNBIChwcml2YXRlKScpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSBjKCJjb3VudHJ5IiwiLnZhbHVlIiksIG5hbWVzX3NlcCA9ICJfIikgJT4lCiAgcGl2b3RfbG9uZ2VyKDM6NCwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIGdncGxvdCgpICsKICBzdGF0X3Ntb290aChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSwgY29sb3IgPSBjb3VudHJ5LCBsaW5ldHlwZSA9IHR5cGUpLCAKICAgICAgICAgICAgICBmb3JtdWxhID0geX54LCBtZXRob2QgPSAibG9lc3MiLCBzcGFuID0gMC4yNSwgc2UgPSBGQUxTRSwgc2l6ZT0wLjc1KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDguIFRoZSByaXNlIG9mIHByaXZhdGUgdmVyc3VzIHRoZSBkZWNsaW5lIG9mIHB1YmxpYyB3ZWFsdGggCiAgICAgICBcbmluIHJpY2ggY291bnRyaWVzLCAxOTcwLTIwMjAiLCAKICAgICAgIHggPSAiIiwgeSA9ICJ3ZWFsdGggYXMgYXMgJSBvZiBuYXRpb25hbCBpbmNvbWUiLCBjb2xvciA9ICIiLCB0eXBlID0gIiIpCmBgYAoKCi0tLQoKYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGZfZjggJT4lIAogIHNlbGVjdCh5ZWFyLCBHZXJtYW55X3B1YmxpYyA9IEdlcm1hbnksIEdlcm1hbnlfcHJpdmF0ZSA9ICdHZXJtYW55IChwcml2YXRlKScsIAogICAgICAgICBTcGFpbl9wdWJsaWMgPSBTcGFpbiwgU3BhaW5fcHJpdmF0ZSA9ICdTcGFpbiAocHJpdmF0ZSknLCAKICAgICAgICAgRnJhbmNlX3B1YmxpYyA9IEZyYW5jZSwgRnJhbmNlX3ByaXZhdGUgPSAnRnJhbmNlIChwcml2YXRlKScsIAogICAgICAgICBVS19wdWJsaWMgID0gVUssIFVLX3ByaXZhdGUgPSAnVUsgKHByaXZhdGUpJywgCiAgICAgICAgIEphcGFuX3B1YmxpYyA9IEphcGFuLCBKYXBhbl9wcml2YXRlID0gJ0phcGFuIChwcml2YXRlKScsIAogICAgICAgICBOb3J3YXlfcHVibGljID0gTm9yd2F5LCBOb3J3YXlfcHJpdmF0ZSA9ICdOb3J3YXkgKHByaXZhdGUpJywKICAgICAgICAgVVNBX3B1YmxpYyA9IFVTQSwgVVNBX3ByaXZhdGUgPSAnVVNBIChwcml2YXRlKScpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSBjKCJjb3VudHJ5IiwiLnZhbHVlIiksIG5hbWVzX3NlcCA9ICJfIikgJT4lCiAgcGl2b3RfbG9uZ2VyKDM6NCwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIGdncGxvdCgpICsKICBzdGF0X3Ntb290aChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSwgY29sb3IgPSBjb3VudHJ5LCBsaW5ldHlwZSA9IHR5cGUpLCAKICAgICAgICAgICAgICBmb3JtdWxhID0geX54LCBtZXRob2QgPSAibG9lc3MiLCBzcGFuID0gMC4yNSwgc2UgPSBGQUxTRSwgc2l6ZT0wLjc1KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDguIFRoZSByaXNlIG9mIHByaXZhdGUgdmVyc3VzIHRoZSBkZWNsaW5lIG9mIHB1YmxpYyB3ZWFsdGggCiAgICAgICBcbmluIHJpY2ggY291bnRyaWVzLCAxOTcwLTIwMjAiLCAKICAgICAgIHggPSAiIiwgeSA9ICJ3ZWFsdGggYXMgYXMgJSBvZiBuYXRpb25hbCBpbmNvbWUiLCBjb2xvciA9ICIiLCB0eXBlID0gIiIpCmBgYAoKLS0tCgojIyMgRjE1OiBQZXIgY2FwaXRhIGVtaXNzaW9ucyBhY3Jpc3MgdGhlIHdvcmxkLCAyMDE5IC0gYWRkIHJvdyBuYW1lcyArIGRvZGdlCgpgYGB7ciBkYXRhLWYxNSwgY2FzaCA9IFRSVUV9CmRmX2YxNSA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUYxNSIpOyBkZl9mMTUKYGBgCgotLS0KCmBgYHtyIGV2YWwgPSBGQUxTRX0KZGZfZjE1ICU+JSBtdXRhdGUocmVnaW9uID0gcmVwKHJlZ2lvbldJRFshaXMubmEocmVnaW9uV0lEKV0sIGVhY2ggPSAzKSkgJT4lCiAgc2VsZWN0KHJlZ2lvbiwgZ3JvdXAsIHRjYXApICU+JQogIGdncGxvdChhZXMoeCA9IHJlZ2lvbiwgeSA9IHRjYXAsIGZpbGwgPSBncm91cCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcCh4LCB3aWR0aCA9IDEwKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDE1IFBlciBjYXBpdGEgZW1pc3Npb25zIGFjcm9zcyB0aGUgd29ybGQsIDIwMTkiLCAKICAgICAgIHggPSAiIiwgeSA9ICJ0b25uZXMgb2YgQ08yZSBwZXIgcGVyc29uIHBlciB5ZWFyIiwgZmlsbCA9ICIiKQpgYGAKCgotLS0KCmBgYHtyIGVjaG8gPSBGQUxTRX0KZGZfZjE1ICU+JSBtdXRhdGUocmVnaW9uID0gcmVwKHJlZ2lvbldJRFshaXMubmEocmVnaW9uV0lEKV0sIGVhY2ggPSAzKSkgJT4lCiAgc2VsZWN0KHJlZ2lvbiwgZ3JvdXAsIHRjYXApICU+JQogIGdncGxvdChhZXMoeCA9IHJlZ2lvbiwgeSA9IHRjYXAsIGZpbGwgPSBncm91cCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcCh4LCB3aWR0aCA9IDEwKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDE1IFBlciBjYXBpdGEgZW1pc3Npb25zIGFjcm9zcyB0aGUgd29ybGQsIDIwMTkiLCAKICAgICAgIHggPSAiIiwgeSA9ICJ0b25uZXMgb2YgQ08yZSBwZXIgcGVyc29uIHBlciB5ZWFyIiwgZmlsbCA9ICIiKQpgYGAKCgojIyBFREEgV29ya2Zsb3cKCiMjIyBFREEgU3RlcCAwCgoxLiBDaG9vc2UgYW5kIGNsYXJpZnkgYSB0b3BpYyB0byBzdHVkeS4KMi4gTGlzdCBxdWVzdGlvbnMgdG8gc3R1ZHkKMy4gRmluZCBkYXRhOgogIC0gbGluayB0byBkYXRhIHdpdGggYSB1cmw6IHVuaXZlcnNhbCByZXNvdXJjZSBsb2NhdG9yIGluIGEgd2VicGFnZQogIC0gZG93bmxvYWQgZGF0YSBpbiBjc3YsIEV4Y2VsLCBldGMuCgpSZXBlYXQgdGhlIHByb2Nlc3MgZHVyaW5nIHlvdXIgRURBLgoKCiFbaW1hZ2VdKGRhdGEvZGF0YS1zY2llbmNlLnBuZykKCiMjIyBFREEgYnkgUiBTdHVkaW86IFN0ZXAgMQoKSW4gUlN0dWRpbywKCjEuMS4gUHJvamVjdAoKICAqIENyZWF0ZSBhIG5ldyBwcm9qZWN0OiBGaWxlID4gTmV3IFByb2plY3Q7IG9yICAKICAqIE9wZW4gYSBwcm9qZWN0OiBGaWxlID4gT3BlbiBQcm9qZWN0LCBPcGVuIFByb2plY3QgaW4gTmV3IFNlc3Npb24sIE9wZW4gUmVjZW50IFByb2plY3QgIAogICogX0NoZWNrIHRoZXJlIGlzIGEgZmlsZSBgcHJvamVjdF9uYW1lLlJwcm9qYCBpbiB5b3VyIHByb2plY3QgZm9sZGVyIChkaXJlY3RvcnkpXwoKIAoxLjIuIGRhdGEgZm9sZGVyIChkaXJlY3RvcnkpIGBkYXRhYAoKICAqIENyZWF0ZSBhIGRhdGEgZm9sZGVyOiBQcmVzcyBOZXcgRm9sZGVyIGF0IHRoZSByaWdodCBib3R0b20gcGFuZTsgb3IgCiAgKiBDb25maXJtIHRoZSBkYXRhIGZvbGRlciBwcmV2aW91c2x5IGNyZWF0ZWQ6IFByZXNzIEZpbGVzIGF0IHRoZSByaWdodCBib3R0b20gcGFuZQogICogX0lmIHlvdSBmb2xsb3cgMSwgdGhlIGRhdGEgZm9sZGVyIGV4aXN0cyBpbiB5b3VyIHByb2plY3QgZm9sZGVyXwoKIAoxLjMuIE1vdmUgKG9yIGNvcHkpIGRhdGEgZm9yIHRoZSBwcm9qZWN0IHRvIHRoZSBkYXRhIGZvbGRlcgoKICAqIElmIHlvdSBkb3dubG9hZGVkIHRoZSBkYXRhLCBpdCBpcyBpbiB5b3VyIERvd25sb2FkIGZvbGRlci4gTW92ZSBpdCB0byBgZGF0YWAuCiAgKiBfQ2hlY2sgaW4geW91ciBSU3R1ZGlvIHRoYXQgeW91ciBkYXRhIGlzIGluIGBkYXRhYDogUHJlc3MgRmlsZXMgYXQgdGhlIHJpZ2h0IGJvdHRvbSBwYW5lIGFuZCBjbGljayBgZGF0YWAsIHRoZSBkYXRhIGZvbGRlci5fCiAgCgotLS0KCiMjIyBFREEgYnkgUiBTdHVkaW86IFN0ZXAgMgoKMi4xLiBQcm9qZWN0IE5vdGVib29rOiBNZW1vCgogIC0gQ3JlYXRlIGFuIFIgTm90ZWJvb2s6IEZpbGUgPiBOZXcgRmlsZSA+IFIgTm90ZWJvb2sKICAKICAgICsgWW91IGNhbiB1c2UgUiBOb3RlYm9vayB0ZW1wbGF0ZSBpbiBNb29kbGUgYnkgbW92aW5nIHRoZSB0ZW1wbGF0ZSAodGVtcGxhdGUuUm1kIG9yIHRlbXBsYXRlLm5iLlJtZCkgZmlsZSBpbiB5b3VyIHByb2plY3QgZm9sZGVyIG9yIGNvcHkgYW5kIHBhc3RlIHRoZSB0ZXh0IGZpbGUgaW50byB5b3VyIG5ldyBSIE5vdGVib29rLgogICAgKyBJZiB5b3UgdXNlIHRlbXBsYXRlLm5iLlJtZCAoUiBOb3RlYm9vayBGaWxlKSwgY2hvb3NlIE9wZW4gaW4gRWRpdG9yLgogICAgCiAgLSBBZGQgZGVzY3JpcHRpdmUgdGl0bGUuIAogIAoyLjIuIFNldHVwIENvZGUgQ2h1bmsgCgogIC0gQ3JlYXRlIGEgY29kZSBjaHVuayBhbmQgYWRkIHBhY2thZ2VzIHRvIHVzZSBpbiB0aGUgcHJvamVjdCBhbmQgUlVOIHRoZSBjb2RlLgogIAogICAgICArIGxpYnJhcnkodGlkeXZlcnNlKQogICAgICArIGxpYnJhcnkoV0RJKQogICAgICArIG9yIGFueSBvdGhlciBwYWNrYWdlcwoKLS0tCgoyLjMuIENob29zZSBgU291cmNlYCBvciBgVmlzdWFsYCBlZGl0b3IgbW9kZSwgYW5kIHN0YXJ0IGVkaXRpbmcgUHJvamVjdCBOb3RlYm9vawoKICAtIFNldCB1cCBIZWFkaW5ncyBzdWNoIGFzOiBBYm91dCwgRGF0YSwgQW5hbHlzaXMgYW5kIFZpc3VhbGl6YXRpb25zLCBDb25jbHVzaW9ucwogIC0gVW5kZXIgQWJvdXQgb3IgRGF0YSwgcGFzdGUgdXJsIG9mIHRoZSBzaXRlcyBhbmQvb3IgdGhlIGRhdGEKCiAgICAgICsgZWcuIFdvcmxkIERldmVsb3BtZW50IEluZGljYXRvcjoKICAgICAgaHR0cHM6Ly9kYXRhdG9waWNzLndvcmxkYmFuay5vcmcvd29ybGQtZGV2ZWxvcG1lbnQtaW5kaWNhdG9ycy8pCiAgICAgICsgZWcuIFB1YmxpYyBleHBlbmRpdHVyZSBvbiBlZHVjYXRpb246CiAgICAgIGh0dHBzOi8vZGF0YS51bi5vcmcvX0RvY3MvU1lCL0NTVi9TWUI2NV8yNDVfMjAyMjA5X1B1YmxpYyUKICAgICAgMjBleHBlbmRpdHVyZSUyMG9uJTIwZWR1Y2F0aW9uLmNzdikKCgoyLjQuIEVkaXQgYSBuZXcgZmlsZSBieSBzYXZpbmcgYXMgZm9yIGEgcmVwb3J0CgogIC0gRmlsZSA+IFNhdmUgQXMuLi4KCi0tLQoKIyMjIEVEQSBieSBSIFN0dWRpbzogU3RlcCAzIC0gSW1wb3J0aW5nIERhdGEKCkFzc2lnbiBhIG5hbWUgeW91IGNhbiByZWNhbGwgZWFzaWx5IHdoZW4geW91IGltcG9ydCBkYXRhLiBZb3UgbWF5IG5lZWQgdG8gcmVsb2FkIHRoZSBkYXRhIHdpdGggb3B0aW9ucy4KCjMuMS4gVXNlIGEgcGFja2FnZToKCiAgKiBXREksIHdpciwgZXVyb3N0YXQsIGV0Yy8KICAqIGB3ZGlfc2hvcnRuYW1lIDwtIFdESShpbmRpY2F0b3IgPSAiaW5kaWNhdG9yJ3MgbmFtZSIsIC4uLiApCiAgKiBTdG9yZSB0aGUgZGF0YSBhbmQgdXNlIGl0OiBgd3JpdGVfY3N2KHdkaV9zaG9ydG5hbWUsICJkYXRhL3dkaV9zaG9ydG5hbWUuY3N2IilgCiAgKiBgd2RpX3Nob3J0bmFtZSA8LSByZWFkX2NzdigiZGF0YS93ZGlfc2hvcnRuYW1lLmNzdiIpYAogIAozLjIuIFVzZSBgcmVhZHJgIHRvIHJlYWQgZnJvbSBgZGF0YWAsIHlvdXIgZGF0YSBmb2xkZXIKCiAgKiBgZGYxX3Nob3J0bmFtZSA8LSByZWFkX2NzdigiZGF0YS9maWxlX25hbWUuY3N2IilgCgotLS0KCjMuMy4gVXNlIGByZWFkcmAgdG8gcmVhZCB1c2luZyB0aGUgdXJsIG9mIHRoZSBkYXRhCgogICogYGRmMl9zaG9ydG5hbWUgPC0gcmVhZF9jc3YoInVybF9vZl90aGVfZGF0YSIpYAogICogU3RvcmUgdGhlIGRhdGEgYW5kIHVzZSBpdDogYHdyaXRlX2NzdihkZjJfc2hvcnRuYW1lLCAiZGF0YS9kZjJfc2hvcnRuYW1lLmNzdiIpYAogICogYGRmMl9zaG9ydG5hbWUgPC0gcmVhZF9jc3YoImRhdGEvZGYyX3Nob3J0bmFtZS5jc3YiKWAKICAKMy41LiBVc2UgYHJlYWR4bGAgdG8gcmVhZCBFeGNlbCBkYXRhLiBBZGQgYGxpYnJhcnkocmVhZHhsKWAgaW4gdGhlIHNldHVwIGFuZCBydW4uCgogICogYGRmNCA8LSByZWFkX2V4Y2VsKCJkYXRhL2ZpbGVfbmFtZS54bHN4Iiwgc2hlZXQgPSAxKWAKICAKUmVmZXJlbmNlczogQ2hlYXQgU2hlZXQgLSBgcmVhZHJgLCBbcmVhZHJdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZyksIFtyZWFkeGxdKGh0dHBzOi8vcmVhZHhsLnRpZHl2ZXJzZS5vcmcpCgoKLS0tCgojIyMgRURBIGJ5IFIgU3R1ZGlvOiBTdGVwIDQgLSBEYXRhIFRyYXNuZm9ybWF0aW9uCgo0LjEuIExvb2sgYXQgdGhlIGRhdGE6IHN1cHBvc2UgYGRmYCBpcyB0aGUgZGF0YSBmcmFtZQoKICAqIEl0IGlzIGEgZ29vZCBvcHRpb24gdG8gY2hhbmdlIGludG8gYSB0aWJibGU6IGBkdCA8LSBhc190aWJibGUoZGYpYAogICogYGhlYWQoZGYpYCwgYHN0cihkZilgLCBgc3VtbWFyeShkZilgLCBgZHRgLCBgZ2xpbXBzZShkdClgCgo0LjIuIExvb2sgYXQgZWFjaCB2YXJpYWJsZQoKICAqIGNhdGVnb3JpY2FsPyBudW1lcmljYWw/IAogICogZmFjdG9yPyAtIFtmb3JjYXRzXShodHRwczovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZykKICAKNC4zLiBWYXJpYXRpb24gb2YgZWFjaCBkYXRhOiBzdXBwb3NlIGB4MWAgaXMgYSBjb2x1bW4gbmFtZS4KCiAgKiBgZGYgJT4lIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHgxKSwgYmlucyA9IDMwKWAKICAqIGBkZiAlPiUgZHJvcF9uYSh4MSlgOiBzZWUgdGhlIHJvd3Mgd2l0aCBhIHZhbHVlIGluIGB4MWAuIElmIHRoZSB2YWx1ZSBpcyBOQSwgdGhlIHJvdyBpcyBub3Qgc2hvd24uCiAgCiAgICAtIGBkZl93b19uYSA8LSBkZiAlPiUgZHJvcF9uYSh4MSlgIGlmIHlvdSB3YW50IHRvIHVzZSBvbmx5IHRoZSByb3dzIHdpdGhvdXQgTkEgaW4gYHgxYAogICAgCi0tLQoKNC40LiBVc2UgYGRweWxyYCBhbmQgYHRpZHlyYCB0byBjaGFuZ2UgY29sdW1uIG5hbWVzLCB0aWR5IGRhdGEsIGFuZC9vciBzdW1tYXJpemUgZGF0YQoKICAqIGByZW5hbWVgLCBgc2VsZWN0YCwgYGZpbHRlcmAsIGBhcnJhbmdlYCwgYG11dGF0ZWAsIGBwaXZvdF9sb25nZXIoKWAsIGBwaXZvdF93aWRlcigpYCwgYGdyb3VwX2J5YCBhbmQgYHN1bW1hcml6ZWAKCgpSZWZlcmVuY2VzOiBDaGVhdCBTaGVldCAtIGBkcGx5cmAgYW5kIGB0aWR5cmAsIFtkcGx5cl0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnKSwgW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcpCgotLS0KCiMjIyBFREEgYnkgUiBTdHVkaW86IFN0ZXAgNSAtIFZpc3VhbGl6ZSBEYXRhCgo1LjEuIEluIGNvbWJpbmF0aW9uIHdpdGggU3RhcCA0IC0gZGF0YSB0cmFuc2Zvcm1hdGlvbiwgdHJ5IHZhcmlvdXMgZGF0YSB2aXN1YWxpemF0aW9uLgoKICAqIFdoYXQgdHlwZSBvZiB2YXJpYXRpb24gb2NjdXJzIHdpdGhpbiBteSB2YXJpYWJsZXM/CiAgKiBXaGF0IHR5cGUgb2YgY292YXJpYXRpb24gb2NjdXJzIGJldHdlZW4gbXkgdmFyaWFibGVzPwoKCjUuMi4gS2VlcCBhIHJlY29yZCBvZiB3aGF0IHlvdSBjYW4gb2JzZXJ2ZSBieSB0aGUgdmlzdWFsaXphdGlvbgoKNS4zLiBFZGl0IHRoZSBsaXN0IG9mIHF1ZXN0aW9ucyBieSBhZGRpbmcgb3IgcG9saXNoaW5nCgo1LjQuIFNlbGVjdCBzZXZlcmFsIGluZm9ybWF0aXZlIGNoYXJ0IGFuZCBhZGQgb3B0aW9ucwoKNS41LiBMb29rIGF0IGV4YW1wbGVzIGZyb20gdGhlIHRleHRib29rcyBvciB0ZWFjaGluZyBzaXRlIHRvIGhhdmUgYmV0dGVyIHZpc3VhbGl6YXRpb24KClJlZmVyZW5jZXM6IENoZWF0IFNoZWV0IC0gYGdncGxvdDJgIFtnZ3Bsb3QyXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZyksIFtnZ3Bsb3QyIGJvb2tdKGh0dHBzOi8vZ2dwbG90Mi1ib29rLm9yZykKCi0tLQoKIyMjIEVEQSBieSBSIFN0dWRpbzogU3RlcCA2IC0gQ29uY2x1c2lvbnMgYW5kIFF1ZXN0aW9ucyBmb3IgRnVydGhlciBTdHVkeQoKMS4gRURBIGlzIGFuIGl0ZXJhdGl2ZSBjeWNsZSB0aGF0IGhlbHBzIHlvdSB1bmRlcnN0YW5kIHdoYXQgeW91ciBkYXRhIHNheXMuIFdoZW4geW91IGRvIEVEQSwgeW91OgoKMi4gR2VuZXJhdGUgcXVlc3Rpb25zIGFib3V0IHlvdXIgZGF0YQoKMy4gU2VhcmNoIGZvciBhbnN3ZXJzIGJ5IHZpc3VhbGlzaW5nLCB0cmFuc2Zvcm1pbmcsIGFuZC9vciBtb2RlbGluZyB5b3VyIGRhdGEKClVzZSB3aGF0IHlvdSBsZWFybiB0byByZWZpbmUgeW91ciBxdWVzdGlvbnMgYW5kL29yIGdlbmVyYXRlIG5ldyBxdWVzdGlvbnMKCkVEQSBpcyBhbiBpbXBvcnRhbnQgcGFydCBvZiBhbnkgZGF0YSBhbmFseXNpcy4gWW91IGNhbiB1c2UgRURBIHRvIG1ha2UgZGlzY292ZXJpZXMgYWJvdXQgdGhlIHdvcmxkOyBvciB5b3UgY2FuIHVzZSBFREEgdG8gZW5zdXJlIHRoZSBxdWFsaXR5IG9mIHlvdXIgZGF0YSwgYXNraW5nIHF1ZXN0aW9ucyBhYm91dCB3aGV0aGVyIHRoZSBkYXRhIG1lZXRzIHlvdXIgc3RhbmRhcmRzIG9yIG5vdC4KCi0tLQoKIyMjIEV4YW1wbGU6IFdESQoKKiBHb3Zlcm5tZW50IGV4cGVuZGl0dXJlIG9uIGVkdWNhdGlvbiwgdG90YWwgKCUgb2YgR0RQKQoKICAtIGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9TRS5YUEQuVE9UTC5HRC5aUwogIAoqIElEOiBTRS5YUEQuVE9UTC5HRC5aUwoKLS0tCgojIyMgRXhhbXBsZTogV0lSMjAyMgoKYGBge3Igd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0KZGZfZjggJT4lIAogIHNlbGVjdCh5ZWFyLCBHZXJtYW55X3B1YmxpYyA9IEdlcm1hbnksIEdlcm1hbnlfcHJpdmF0ZSA9ICdHZXJtYW55IChwcml2YXRlKScsIAogICAgICAgICBTcGFpbl9wdWJsaWMgPSBTcGFpbiwgU3BhaW5fcHJpdmF0ZSA9ICdTcGFpbiAocHJpdmF0ZSknLCAKICAgICAgICAgRnJhbmNlX3B1YmxpYyA9IEZyYW5jZSwgRnJhbmNlX3ByaXZhdGUgPSAnRnJhbmNlIChwcml2YXRlKScsIAogICAgICAgICBVS19wdWJsaWMgID0gVUssIFVLX3ByaXZhdGUgPSAnVUsgKHByaXZhdGUpJywgCiAgICAgICAgIEphcGFuX3B1YmxpYyA9IEphcGFuLCBKYXBhbl9wcml2YXRlID0gJ0phcGFuIChwcml2YXRlKScsIAogICAgICAgICBOb3J3YXlfcHVibGljID0gTm9yd2F5LCBOb3J3YXlfcHJpdmF0ZSA9ICdOb3J3YXkgKHByaXZhdGUpJywKICAgICAgICAgVVNBX3B1YmxpYyA9IFVTQSwgVVNBX3ByaXZhdGUgPSAnVVNBIChwcml2YXRlKScpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSBjKCJjb3VudHJ5IiwiLnZhbHVlIiksIG5hbWVzX3NlcCA9ICJfIikgJT4lCiAgcGl2b3RfbG9uZ2VyKDM6NCwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIGdncGxvdCgpICsKICBzdGF0X3Ntb290aChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSwgY29sb3IgPSBjb3VudHJ5LCBsaW5ldHlwZSA9IHR5cGUpLCBmb3JtdWxhID0geX54LCBtZXRob2QgPSAibG9lc3MiLCBzcGFuID0gMC4yNSwgc2UgPSBGQUxTRSwgc2l6ZT0wLjc1KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDguIFRoZSByaXNlIG9mIHByaXZhdGUgdmVyc3VzIHRoZSBkZWNsaW5lIG9mIHB1YmxpYyB3ZWFsdGggXG5pbiByaWNoIGNvdW50cmllcywgMTk3MC0yMDIwIiwgCiAgICAgICB4ID0gIiIsIHkgPSAid2VhbHRoIGFzIGFzICUgb2YgbmF0aW9uYWwgaW5jb21lIiwgY29sb3IgPSAiIiwgdHlwZSA9ICIiKQpgYGAKCiMjIFRoZSBXZWVrIEZpdmUgQXNzaWdubWVudCAoaW4gTW9vZGxlKQoKKipgdGlkeXJgIGFuZCBXSVIyMDIyKioKCiogQ3JlYXRlIGFuIFIgTm90ZWJvb2sgb2YgYSBEYXRhIEFuYWx5c2lzIGNvbnRhaW5pbmcgdGhlIGZvbGxvd2luZyBhbmQgc3VibWl0IHRoZSByZW5kZXJlZCBIVE1MIGZpbGUgKGVnLiBgYTNfMTIzNDU2Lm5iLmh0bWxgICBieSByZXBsYWNpbmcgMTIzNDU2IHdpdGggeW91ciBJRCkKICAxLiBjcmVhdGUgYW4gUiBOb3RlYm9vayB1c2luZyB0aGUgUiBOb3RlYm9vayBUZW1wbGF0ZSBpbiBNb29kbGUsICBzYXZlIGFzIGBhM18xMjM0NTYuUm1kYCwgCiAgMi4gd3JpdGUgeW91ciBuYW1lIGFuZCBJRCBhbmQgdGhlIGNvbnRlbnRzLCAKICAzLiBydW4gZWFjaCBjb2RlIGJsb2NrLCAKICA0LiBwcmV2aWV3IHRvIGNyZWF0ZSBgYTNfMTIzNDU2Lm5iLmh0bWxgLAogIDUuIHN1Ym1pdCAgYGEzXzEyMzQ1Ni5uYi5odG1sYCB0byBNb29kbGUuCgoxLiBDaG9vc2UgYSBkYXRhIHdpdGggYXQgbGVhc3QgdHdvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBhbmQgYXQgbGVhc3QgdHdvIG51bWVyaWNhbCB2YXJpYWJsZXMuCgogICAgLSBJbmZvcm1hdGlvbiBvZiB0aGUgZGF0YTogTmFtZSwgSW5kaWNhdG9yLCBEZXNjcmlwdGlvbiwgU291cmNlLCBldGMuCiAgICAtIEV4cGxhaW4gd2h5IHlvdSBjaG9zZSB0aGUgaW5kaWNhdG9yCiAgICAtIExpc3QgcXVlc3Rpb25zIHlvdSB3YW50IHRvIHN0dWR5CgotLS0KCjIuIEV4cGxvcmUgdGhlIGRhdGEgdXNpbmcgdmlzdWFsaXphdGlvbiB1c2luZyBgZ2dwbG90MmAKCiAgICAtIENyZWF0ZSB2YXJpb3VzIGNoYXJ0cwogICAgLSBDcmVhdGUgYXQgbGVhc3Qgb25lIGNoYXJ0IHdpdGggYXQgbGVhc3QgdHdvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBhbmQgYXQgbGVhc3Qgb25lIG51bWVyaWNhbCB2YXJpYWJsZS4KICAgIC0gQ3JlYXRlIGF0IGxlYXN0IG9uZSBjaGFydCB3aXRoIGF0IGxlYXN0IHR3byBudW1lcmljYWwgdmFyaWFibGVzIGFuZCBhdCBsZWFzdCBvbmUgY2F0ZWdvcmljYWwgdmFyaWFibGUuCgozLiBPYnNlcnZhdGlvbnMgYmFzZWQgb24geW91ciBkYXRhIHZpc3VhbGl6YXRpb24sIGFuZCBkaWZmaWN1bHRpZXMgYW5kIHF1ZXN0aW9ucyBlbmNvdW50ZXJlZCBpZiBhbnkuCgoqKkR1ZToqKiAyMDIzLTAxLTIzIDIzOjU5OjAwLiBTdWJtaXQgeW91ciBSIE5vdGVib29rIGZpbGUgaW4gTW9vZGxlIChUaGUgRm91cnRoIEFzc2lnbm1lbnQpLiBEdWUgb24gTW9uZGF5IQoKCiMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAoRURBKSBWICAKCiMjIE1vZGVsaW5nCgo+IOKAnFRpZHkgZGF0YSBzZXRzIGFyZSBhbGwgYWxpa2U7IGJ1dCBldmVyeSBtZXNzeSBkYXRhIHNldCBpcyBtZXNzeSBpbiBpdHMgb3duIHdheS7igJ0g4oCUIEhhZGxleSBXaWNraGFtCgo+IOKAnGFsbCBoYXBweSBmYW1pbGllcyBhcmUgYWxsIGFsaWtlOyBlYWNoIHVuaGFwcHkgZmFtaWx5IGlzIHVuaGFwcHkgaW4gaXRzIG93biB3YXnigJ0gLSBUb2xzdG95J3MgQW5uYSBLYXJlbmluYQoKCkNvcnJlbGF0aW9uCgpgYGB7cn0KaXJpcyAlPiUgc2VsZWN0KC01KSAlPiUgY29yKCkKYGBgCgpHYWx0b24ncyBkYXRhLiBSZWdyZXNzaW9uLgoKCk5vcm1hbGl6YXRpb24sIHN0YW5kYWxpemF0aW9uCgpTREdzIEFjYWRlbXkKClRyZW5kCgoKYGBge3J9CmRmNCA8LSBXREkoCiAgY291bnRyeT0iYWxsIiwKICBpbmRpY2F0b3IgPSBjKCJTUC5QT1AuVE9UTCIsIk1TLk1JTC5YUE5ELkdELlpTIiwiTVMuTUlMLlRPVEwuUDEiLCJOWS5HRFAuTUtUUC5DRCIpLAogIHN0YXJ0ID0gMTk2MCwKICBlbmQgPSBOVUxMLAogIGV4dHJhID0gRkFMU0UsCiAgY2FjaGUgPSBOVUxMLAogIGxhdGVzdCA9IE5VTEwsCiAgbGFuZ3VhZ2UgPSAiZW4iCikKYGBgCgpgYGB7cn0KY29sbmFtZXMoZGY0KSA8LSBjKCJDb3VudHJ5IiwiaXNvMmMiLCJpc28zYyIsIlllYXIiLCJQb3B1bGF0aW9uIiwiTWlsX0V4cCIsIlRvdGFsX01pbF9IQyIsIkdEUCIpCmRmNApgYGAKCiMjIyBUYWxpCgpgYGB7cn0KZGZfd2RpX3BvdmVydHkgPC0gV0RJKAogIGNvdW50cnkgPSAiYWxsIiwgCiAgaW5kaWNhdG9yID0gYyhuYXRpb25hbF9wb3ZlcnR5X3JhdGUgPSAiU0kuUE9WLk5BSEMiLCBtdWx0aWRpbWVudGlvbmFsX3BvdmVydHlfcmF0ZSA9ICJTSS5QT1YuTURJTSIsIGdkcFBlcmNhcCA9ICJOWS5HRFAuUENBUC5LRCIsIGdpbmlfaW5keCA9ICJTSS5QT1YuR0lOSSIpLCBzdGFydCA9IDE5OTAsCiAgICBlbmQgPSAyMDIxLAogIGV4dHJhID0gVFJVRQopCmBgYAoKYGBge3J9CmRmX3dkaV9wb3ZlcnR5ICU+JSAgCiAgZ3JvdXBfYnkoY291bnRyeSwgeWVhcikgJT4lCiAgbXV0YXRlKG1lYW5fZ2RwX2NvdW50cnkgPSBtZWFuKGdkcFBlcmNhcCkpICU+JQogIG11dGF0ZShtZWFuX3BvdmVydHlfY291bnRyeT0gbWVhbihuYXRpb25hbF9wb3ZlcnR5X3JhdGUpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgICBmaWx0ZXIoIWlzLm5hKGluY29tZSkpICU+JSAgIGZpbHRlcighKGluY29tZT09IkFnZ3JlZ2F0ZXMiKSkgJT4lIGdncGxvdChhZXMoeCA9IGxvZzEwKG1lYW5fZ2RwX2NvdW50cnkpKSkgKyBnZW9tX3BvaW50KGFlcyh5ID0gbWVhbl9wb3ZlcnR5X2NvdW50cnksIGNvbG9yID0gaW5jb21lKSkgKyAgbGFicyh4ID0gIkdEUCBwZXIgY2FwaXRhIiwgeSA9ICJwb3ZlcnR5IHJhdGUgKCUgb2YgcG9wdWxhdGlvbikiLCB0aXRsZSA9ICJQb3ZlcnR5IHJhdGVzIGFuZCBHRFAgcGVyIGNhcGl0YSIsIHN1YnRpdGxlPSJ3b3JsZCBjb3VudHJpZXMsIDE5OTAtMjAyMSBhdmVyYWdlLCBieSBpbmNvbWUgbGV2ZWwiKQpgYGAKCmBgYHtyfQpkZl93ZGlfcG92ZXJ0eSAlPiUgIAogIGdyb3VwX2J5KGNvdW50cnksIHllYXIpICU+JQogIG11dGF0ZShtZWFuX2dkcF9jb3VudHJ5ID0gbWVhbihnZHBQZXJjYXApKSAlPiUKICBtdXRhdGUobWVhbl9tdWx0aXBvdmVydHlfY291bnRyeT0gbWVhbihtdWx0aWRpbWVudGlvbmFsX3BvdmVydHlfcmF0ZSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICAgIGZpbHRlcighKHJlZ2lvbj09IkFnZ3JlZ2F0ZXMiKSkgJT4lIGZpbHRlcighaXMubmEocmVnaW9uKSkgJT4lIGdncGxvdChhZXMoeCA9IGxvZzEwKG1lYW5fZ2RwX2NvdW50cnkpKSkgKyBnZW9tX3BvaW50KGFlcyh5ID0gbWVhbl9tdWx0aXBvdmVydHlfY291bnRyeSwgY29sb3IgPSByZWdpb24pKSArICBsYWJzKHggPSAiR0RQIHBlciBjYXBpdGEiLCB5ID0gIk11bHRpZGltZW50aW5hbCBwb3ZlcnR5IHJhdGUgKCUgb2YgcG9wdWxhdGlvbikiLCB0aXRsZSA9ICJNdWx0aWRpbWVudGlvbmFsIFBvdmVydHkgcmF0ZXMgYW5kIEdEUCBwZXIgY2FwaXRhIiwgc3VidGl0bGU9IndvcmxkIGNvdW50cmllcywgMTk5MC0yMDIxIGF2ZXJhZ2UsIGJ5IHJlZ2lvbiIpCmBgYAoKaW5kZXggc2RnLCBnaGksIGFjYWRlbXkKCm1vb2NzCgpSNERTOiBNb2RlbCBiYXNpY3MKICBodHRwczovL3I0ZHMuaGFkLmNvLm56L21vZGVsLWJhc2ljcy5odG1sCm1vZGVscjogaHR0cHM6Ly9tb2RlbHIudGlkeXZlcnNlLm9yZwoKVGlkeW1vZGVsczogaHR0cHM6Ly93d3cudGlkeW1vZGVscy5vcmcKClRpZHl2ZXJzZSBTa2lsbHMgZm9yIERhdGEgU2NpZW5jZQpodHRwczovL2podWRhdGFzY2llbmNlLm9yZy90aWR5dmVyc2Vjb3Vyc2UvCmh0dHBzOi8vamh1ZGF0YXNjaWVuY2Uub3JnL3RpZHl2ZXJzZWNvdXJzZS9tb2RlbC5odG1sCgoKbWFjaGluZSBsZWFybmluZzpBIEdlbnRsZSBJbnRyb2R1Y3Rpb24gdG8gdGlkeW1vZGVscyBodHRwczovL3J2aWV3cy5yc3R1ZGlvLmNvbS8yMDE5LzA2LzE5L2EtZ2VudGxlLWludHJvLXRvLXRpZHltb2RlbHMvCgpUaWR5IE1vZGVsaW5nIHdpdGggUgpodHRwczovL3d3dy50bXdyLm9yZwoKCiMjIyBPdGhlciBFeGFtcGxlcwoKIyMgUm91ZHVwcwoKIyMjIFIgTWFya2Rvd24gUmV2aXNpdGVkCgojIyMjIExpdGVyYXRlIFByb2dyYW1taW5nIGFuZCBSZXByb2R1Y2libGUgUmVzZWFyY2gKCkltcG9ydGluZyBEYXRhOiAKCjEuIFJlYWQgYSBjc3YgZmlsZTogYHJlYWRfY3N2KCJkYXRhL2ZpbGVfbmFtZS5jc3YiKWAKMi4gRG93bmxvYWQgYW5kIGltcG9ydCB1c2luZyBhIHVybCBvZiBhIGNzdiBmaWxlOiBgcmVhZF9jc3YodXJsKWAKMy4gUmVhZCBhbiBFeGNlbCBmaWxlOiBgcmVhZHhsOjpyZWFkX2V4Y2VsKCJkYXRhL2V4Y2VsX2ZpbGVfbmFtZS54bHN4IilgCjQuIFJlYWQgZnJvbSB0aGUgY2xpcGJvYXJkOiBgcmVhZF9kZWxpbShjbGlwYm9hcmQoKSlgCgogIC0gTm90IHJlcHJvZHVjaWJsZSB1bmxlc3MgY2xlYXJseSBleHBsYWluZWQuCiAgCiMjIyMgQ29kZSBDaHVuayBPcHRpb25zCgpodHRwczovL3lpaHVpLm9yZy9rbml0ci9vcHRpb25zLwoKKiBDaHVuayBOYW1lCiogT3V0cHV0OiB1c2UgZG9jdW1lbnQgZGVmYXVsdAogIC0gU2hvdyBjb2RlIGFuZCBvdXRwdXQ6IGVjaG89VFJVRSwgZXZhbD1UUlVFIC0gRGVmYXVsdAogIC0gU2hvdyBvdXRwdXQgb25seTogZWNobz1GQUxTRQogIC0gU2hvdyBub3RoaW5nIChydW4gY29kZSk6IGluY2x1ZGU9RkFMU0UKICAtIFNob3cgbm90aGluZyAoZG9uJ3QgcnVuIGNvZGUpOiBpbmNsdWRlPUZBTFNFLCBldmFsPUZBTFNFCiogU2hvdyBtZXNzYWdlOiBtZXNzYWdlPVRSVUUsIEZBTFNFCiogU2hvdyB3YXJuaW5nOiB3YXJuaW5nPVRSVUUsIEZBTFNFCiogVXNlIFBhZ2VkIFRhYmxlczogcGFnZWQucHJpbnQ9VFJVRSwgRkFMU0UKKiBVc2UgY3VzdG9tIGZpZ3VyZSBzaXplOiB3aWR0aCBhbmQgaGVpZ2h0IGluIGluY2guCgojIyMjIFByZXNlbnRhdGlvbiBhbmQgUGFwZXIKCjEuIERhdGEgU291cmNlCjIuIFZhcmlhYmxlcwozLiBQcm9ibGVtcwo0LiBWaXN1YWxpemF0aW9uCjUuIE1vZGVsCjYuIENvbmNsdXNpb25zIGFuZCBGdXJ0aGVyIFJlc2VhcmNoCiAKICAgV0RJLCBXSVIsIGV0YwoKIyMjIyBXb3JkCgpDdXN0b20gV29yZCB0ZW1wbGF0ZXM6IGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi1jb29rYm9vay93b3JkLXRlbXBsYXRlLmh0bWwKCllvdSBjYW4gYXBwbHkgdGhlIHN0eWxlcyBkZWZpbmVkIGluIGEgV29yZCB0ZW1wbGF0ZSBkb2N1bWVudCB0byBuZXcgV29yZCBkb2N1bWVudHMgZ2VuZXJhdGVkIGZyb20gUiBNYXJrZG93bi4gU3VjaCBhIHRlbXBsYXRlIGRvY3VtZW50IGlzIGFsc28gY2FsbGVkIGEg4oCcc3R5bGUgcmVmZXJlbmNlIGRvY3VtZW50LuKAnSBUaGUga2V5IGlzIHRoYXQgeW91IGhhdmUgdG8gY3JlYXRlIHRoaXMgdGVtcGxhdGUgZG9jdW1lbnQgZnJvbSBQYW5kb2MgZmlyc3QsIGFuZCBjaGFuZ2UgdGhlIHN0eWxlIGRlZmluaXRpb25zIGluIGl0IGxhdGVyLiBUaGVuIHBhc3MgdGhlIHBhdGggb2YgdGhpcyB0ZW1wbGF0ZSB0byB0aGUgcmVmZXJlbmNlX2RvY3ggb3B0aW9uIG9mIHdvcmRfZG9jdW1lbnQKCmBgYAotLS0KIHdvcmRfZG9jdW1lbnQ6CiAgICByZWZlcmVuY2VfZG9jeDogInRlbXBsYXRlLmRvY3giCi0tLQpgYGAKCiMjIyMgUG93ZXJQb2ludAoKUG93ZXJQb2ludCBwcmVzZW50YXRpb246IGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9wb3dlcnBvaW50LXByZXNlbnRhdGlvbi5odG1sCgpDdXN0b20gdGVtcGxhdGVzOiBodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vcG93ZXJwb2ludC1wcmVzZW50YXRpb24uaHRtbCNwcHQtdGVtcGxhdGVzCgpgYGAKLS0tCiAgcG93ZXJwb2ludF9wcmVzZW50YXRpb246CiAgICByZWZlcmVuY2VfZG9jOiBteS1zdHlsZXMucHB0eAotLS0KYGBgCgpodHRwczovL3N1cHBvcnQubWljcm9zb2Z0LmNvbS9lbi11cy9vZmZpY2UvY3JlYXRlLWFuZC1zYXZlLWEtcG93ZXJwb2ludC10ZW1wbGF0ZS1lZTQ0MjlhZC0yYTc0LTQxMDAtODJmNy01MGY4MTY5YzhhY2EKCllvdVR1YmU6IEhvdyBUbyBDcmVhdGUgQSBQb3dlclBvaW50IFRlbXBsYXRl